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
42typedef 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
49typedef ArgEl InArg;
50
51#define DEFAULT_BDADDR_PROP "persist.service.bdroid.bdaddr"
52
53typedef 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
60typedef 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
69typedef enum _res
70{
71    SUCCESS = 0,
72    FAIL
73}Res;
74
75int 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
93int 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
114void 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
127int 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
181int 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
227int 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