Satish kumar sugasi | bf9558e | 2016-05-10 14:30:17 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2016, The Linux Foundation. All rights reserved. |
| 3 | * |
| 4 | * Redistribution and use in source and binary forms, with or without |
| 5 | * modification, are permitted provided that the following conditions are |
| 6 | * met: |
| 7 | * * Redistributions of source code must retain the above copyright |
| 8 | * notice, this list of conditions and the following disclaimer. |
| 9 | * * Redistributions in binary form must reproduce the above |
| 10 | * copyright notice, this list of conditions and the following |
| 11 | * disclaimer in the documentation and/or other materials provided |
| 12 | * with the distribution. |
| 13 | * * Neither the name of The Linux Foundation nor the names of its |
| 14 | * contributors may be used to endorse or promote products derived |
| 15 | * from this software without specific prior written permission. |
| 16 | * |
| 17 | * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
| 18 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
| 21 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| 24 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| 25 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| 26 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| 27 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 28 | */ |
| 29 | |
| 30 | /* |
| 31 | * FMhal service used to access RFKILL |
| 32 | |
| 33 | **/ |
| 34 | |
| 35 | #include <cutils/log.h> |
| 36 | #include <sys/socket.h> |
| 37 | #include <cutils/sockets.h> |
| 38 | #include <pthread.h> |
| 39 | #include <sys/select.h> |
| 40 | #include <sys/types.h> |
| 41 | #include <sys/stat.h> |
| 42 | #include <stdlib.h> |
| 43 | #include <termios.h> |
| 44 | #include <fcntl.h> |
| 45 | #include <sys/un.h> |
| 46 | #include <sys/eventfd.h> |
| 47 | #include <errno.h> |
| 48 | #include <string.h> |
| 49 | |
| 50 | #include <cutils/properties.h> |
| 51 | #include "private/android_filesystem_config.h" |
| 52 | |
| 53 | |
| 54 | //#include "bt_hci_bdroid.h" |
| 55 | #include "bt_vendor_lib.h" |
| 56 | #include "fm_hci.h" |
| 57 | #include "wcnss_fmhci.h" |
| 58 | #include <dlfcn.h> |
| 59 | |
| 60 | |
| 61 | #define LOG_TAG "FMHalService" |
| 62 | |
| 63 | #define FM_HAL_SOCK "fmhal_sock" |
| 64 | |
| 65 | |
| 66 | #define BT_SSR_TRIGGERED 0xee |
| 67 | |
| 68 | #define FM_POWER_OFF 0x01 |
| 69 | #define FM_POWER_ON 0x02 |
| 70 | #define FM_USERIAL_OPEN 0x03 |
| 71 | #define FM_USERIAL_CLOSE 0x04 |
| 72 | |
| 73 | #define FM_CMD_PACKET_TYPE 0x11 |
| 74 | #define FM_EVT_PACKET_TYPE 0x14 |
| 75 | |
| 76 | #ifndef BLUETOOTH_UID |
| 77 | #define BLUETOOTH_UID 1002 |
| 78 | #endif |
| 79 | #ifndef SYSTEM_UID |
| 80 | #define SYSTEM_UID 1000 |
| 81 | #endif |
| 82 | |
| 83 | #ifndef ROOT_UID |
| 84 | #define ROOT_UID 0 |
| 85 | #endif |
| 86 | |
| 87 | pthread_mutex_t signal_mutex; |
| 88 | |
| 89 | bt_vendor_interface_t *fm_if = NULL; |
| 90 | int remote_fm_hal_fd; |
| 91 | |
| 92 | int do_write(int fd, unsigned char *buf,int len); |
| 93 | |
| 94 | unsigned char reset_cmpl[] = {0x04, 0x0e, 0x04, 0x01,0x03, 0x0c, 0x00}; |
| 95 | |
| 96 | static int extract_uid(int uuid) |
| 97 | { |
| 98 | int userid; |
| 99 | int appid; |
| 100 | |
| 101 | appid = userid = uuid % AID_USER; |
| 102 | if (userid > BLUETOOTH_UID) |
| 103 | { |
| 104 | appid = userid % AID_APP; |
| 105 | } |
| 106 | ALOGD("%s appid = %d",__func__,appid); |
| 107 | return appid; |
| 108 | } |
| 109 | void service_cleanup() |
| 110 | { |
| 111 | char ref_count[PROPERTY_VALUE_MAX]; |
| 112 | char cleanup[PROPERTY_VALUE_MAX]; |
| 113 | int ref_val,clean; |
| 114 | |
| 115 | ALOGE("Service is stopped "); |
| 116 | property_get("wc_transport.clean_up", cleanup, "0"); |
| 117 | property_set("wc_transport.fm_service_status", "0"); |
| 118 | property_set("wc_transport.start_fmhci", "0"); |
| 119 | property_set("wc_transport.fm_power_status", "0"); |
| 120 | clean = atoi(cleanup); |
| 121 | ALOGE("clean Value = %d",clean); |
| 122 | } |
| 123 | |
| 124 | static int establish_fm_remote_socket(char *name) |
| 125 | { |
| 126 | int fd = -1; |
| 127 | struct sockaddr_un client_address; |
| 128 | socklen_t clen; |
| 129 | int sock_id, ret; |
| 130 | struct ucred creds; |
| 131 | int c_uid; |
| 132 | ALOGI("%s(%s) Entry ", __func__, name); |
| 133 | |
| 134 | sock_id = socket(AF_LOCAL, SOCK_STREAM, 0); |
| 135 | if (sock_id < 0) { |
| 136 | ALOGE("%s: server Socket creation failure", __func__); |
| 137 | return fd; |
| 138 | } |
| 139 | |
| 140 | ALOGI("convert name to android abstract name:%s %d", name, sock_id); |
| 141 | if (socket_local_server_bind(sock_id, |
| 142 | name, ANDROID_SOCKET_NAMESPACE_ABSTRACT) >= 0) { |
| 143 | if (listen(sock_id, 5) == 0) { |
| 144 | ALOGI("listen to local socket:%s, fd:%d", name, sock_id); |
| 145 | } else { |
| 146 | ALOGE("listen to local socket:failed"); |
| 147 | close(sock_id); |
| 148 | return fd; |
| 149 | } |
| 150 | } else { |
| 151 | close(sock_id); |
| 152 | ALOGE("%s: server bind failed for socket : %s", __func__, name); |
| 153 | return fd; |
| 154 | } |
| 155 | |
| 156 | clen = sizeof(client_address); |
| 157 | /*Indicate that, server is ready to accept*/ |
| 158 | property_set("wc_transport.fm_service_status", "1"); |
| 159 | ALOGI("%s: wc_transport.fm_service_status set to 1 ", __func__); |
| 160 | ALOGI("%s: before accept_server_socket", name); |
| 161 | fd = accept(sock_id, (struct sockaddr *)&client_address, &clen); |
| 162 | if (fd > 0) { |
| 163 | ALOGI("%s accepted fd:%d for server fd:%d", name, fd, sock_id); |
| 164 | close(sock_id); |
| 165 | |
| 166 | memset(&creds, 0, sizeof(creds)); |
| 167 | socklen_t szCreds = sizeof(creds); |
| 168 | ret = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &creds, &szCreds); |
| 169 | if (ret < 0) { |
| 170 | ALOGE("%s: error getting remote socket creds: %d\n", __func__, ret); |
| 171 | close(fd); |
| 172 | return -1; |
| 173 | } |
| 174 | c_uid = creds.uid; |
| 175 | if (c_uid > BLUETOOTH_UID) |
| 176 | c_uid = extract_uid(creds.uid); |
| 177 | if (c_uid != BLUETOOTH_UID && c_uid != SYSTEM_UID |
| 178 | && c_uid != ROOT_UID) { |
| 179 | ALOGE("%s: client doesn't have required credentials", __func__); |
| 180 | ALOGE("<%s req> client uid: %d", name, creds.uid); |
| 181 | close(fd); |
| 182 | return -1; |
| 183 | } |
| 184 | |
| 185 | ALOGI("%s: Remote socket credentials: %d\n", __func__, creds.uid); |
| 186 | return fd; |
| 187 | } else { |
| 188 | ALOGE("BTC accept failed fd:%d sock d:%d error %s", fd, sock_id, strerror(errno)); |
| 189 | close(sock_id); |
| 190 | return fd; |
| 191 | } |
| 192 | |
| 193 | close(sock_id); |
| 194 | return fd; |
| 195 | } |
| 196 | |
| 197 | |
| 198 | int handle_fmcommand_writes(int fd) { |
| 199 | ALOGI("%s: ", __func__); |
| 200 | unsigned char first_byte; |
| 201 | int retval,val; |
| 202 | int fd_array[CH_MAX]; |
| 203 | |
| 204 | ALOGE("%s: FMHAL: read 1st byte to determine the power on/off ", __func__); |
| 205 | |
| 206 | retval = read (fd, &first_byte, 1); |
| 207 | if (retval < 0) { |
| 208 | ALOGE("%s:read returns err: %d\n", __func__,retval); |
| 209 | return -1; |
| 210 | } |
| 211 | if (retval == 0) { |
| 212 | ALOGE("%s: This indicates the close of other end", __func__); |
| 213 | return -99; |
| 214 | } |
| 215 | |
| 216 | ALOGE("%s: FM command type: 0x%x", __func__, first_byte); |
| 217 | switch(first_byte) { |
| 218 | case FM_POWER_OFF: |
| 219 | ALOGE("%s: Received power off command from FM stack: %d", __func__, first_byte); |
| 220 | val = 0; |
| 221 | retval = fm_if->op(BT_VND_OP_POWER_CTRL, &val); |
| 222 | if (retval < 0) |
| 223 | { |
| 224 | ALOGE("Failed to turn off power from bt vendor interface"); |
| 225 | // return -1; |
| 226 | } |
| 227 | else { |
| 228 | property_set("wc_transport.fm_power_status", "0"); |
| 229 | retval = -99; |
| 230 | } |
| 231 | break; |
| 232 | |
| 233 | case FM_POWER_ON: |
| 234 | ALOGE("%s: Received power ON command from FM stack: %d", __func__, first_byte); |
| 235 | val = 1; |
| 236 | retval =fm_if->op(FM_VND_OP_POWER_CTRL, &val); |
| 237 | if (retval < 0) |
| 238 | { |
| 239 | ALOGE("Failed to turn on power from bt vendor interface"); |
| 240 | } |
| 241 | else |
| 242 | property_set("wc_transport.fm_power_status", "1"); |
| 243 | break; |
| 244 | default: |
| 245 | ALOGE("%s: Unexpected data format!!",__func__); |
| 246 | retval = -1; |
| 247 | } |
| 248 | return retval; |
| 249 | } |
| 250 | |
| 251 | |
| 252 | int do_read(int fd, unsigned char* buf, size_t len) { |
| 253 | int bytes_left, bytes_read = 0, read_offset; |
| 254 | |
| 255 | bytes_left = len; |
| 256 | read_offset = 0; |
| 257 | |
| 258 | do { |
| 259 | bytes_read = read(fd, buf+read_offset, bytes_left); |
| 260 | if (bytes_read < 0) { |
| 261 | ALOGE("%s: Read error: %d (%s)", __func__, bytes_left, strerror(errno)); |
| 262 | return -1; |
| 263 | } else if (bytes_read == 0) { |
| 264 | ALOGE("%s: read returned 0, err = %s, read bytes: %d, expected: %d", |
| 265 | __func__, strerror(errno), (len-bytes_left), len); |
| 266 | return (len-bytes_left); |
| 267 | } |
| 268 | else { |
| 269 | if (bytes_read < bytes_left) { |
| 270 | ALOGV("Still there are %d bytes to read", bytes_left-bytes_read); |
| 271 | bytes_left = bytes_left-bytes_read; |
| 272 | read_offset = read_offset+bytes_read; |
| 273 | } else { |
| 274 | ALOGV("%s: done with read",__func__); |
| 275 | break; |
| 276 | } |
| 277 | } |
| 278 | }while(1); |
| 279 | return len; |
| 280 | } |
| 281 | |
| 282 | int do_write(int fd, unsigned char *buf,int len) |
| 283 | { |
| 284 | int ret = 0; |
| 285 | int write_offset = 0; |
| 286 | int write_len = len; |
| 287 | do { |
| 288 | ret = write(fd, buf+write_offset, write_len); |
| 289 | if (ret < 0) |
| 290 | { |
| 291 | ALOGE("%s: write failed ret = %d err = %s",__func__,ret,strerror(errno)); |
| 292 | return -1; |
| 293 | |
| 294 | } else if (ret == 0) { |
| 295 | ALOGE("%s: Write returned 0, err = %s, Written bytes: %d, expected: %d", |
| 296 | __func__, strerror(errno), (len-write_len), len); |
| 297 | return (len-write_len); |
| 298 | |
| 299 | } else { |
| 300 | if (ret < write_len) |
| 301 | { |
| 302 | ALOGD("%s, Write pending,do write ret = %d err = %s",__func__,ret, |
| 303 | strerror(errno)); |
| 304 | write_len = write_len - ret; |
| 305 | write_offset = ret; |
| 306 | } else if (ret > write_len) { |
| 307 | ALOGE("%s: FATAL wrote more than expected: written bytes: %d expected: %d", |
| 308 | __func__, write_len, ret); |
| 309 | break; |
| 310 | } else { |
| 311 | ALOGV("Write successful"); |
| 312 | break; |
| 313 | } |
| 314 | } |
| 315 | } while(1); |
| 316 | return len; |
| 317 | } |
| 318 | |
| 319 | void vnd_load_if() |
| 320 | { |
| 321 | void *dlhandle; |
| 322 | unsigned char bdaddr[] = {0xaa, 0xbb, 0xcc, 0x11, 0x22, 0x33}; |
| 323 | |
| 324 | dlhandle = dlopen("libbt-vendor.so", RTLD_NOW); |
| 325 | if (!dlhandle) |
| 326 | { |
| 327 | ALOGE("!!! Failed to load libbt-vendor.so !!!"); |
| 328 | return; |
| 329 | } |
| 330 | |
| 331 | fm_if = (bt_vendor_interface_t *) dlsym(dlhandle, "BLUETOOTH_VENDOR_LIB_INTERFACE"); |
| 332 | if (!fm_if) |
| 333 | { |
| 334 | ALOGE("!!! Failed to get bt vendor interface !!!"); |
| 335 | return; |
| 336 | } |
| 337 | |
| 338 | ALOGI("FM-HCI: Registering the WCNSS HAL library by passing CBs and BD addr."); |
| 339 | fm_if->init(&fmhci_vendor_callbacks, bdaddr); |
| 340 | } |
| 341 | |
| 342 | |
| 343 | int main() { |
| 344 | fd_set client_fds; |
Smriti Gupta | c4750ad | 2016-07-08 12:05:57 +0530 | [diff] [blame] | 345 | int retval = -1, n; |
Satish kumar sugasi | bf9558e | 2016-05-10 14:30:17 -0700 | [diff] [blame] | 346 | |
| 347 | ALOGI("%s: Entry ", __func__); |
| 348 | ALOGI("FM HAL SERVICE: Loading the WCNSS HAL library..."); |
| 349 | vnd_load_if(); |
| 350 | ALOGI("create socket"); |
| 351 | remote_fm_hal_fd = establish_fm_remote_socket(FM_HAL_SOCK); |
| 352 | if (remote_fm_hal_fd < 0) { |
| 353 | ALOGE("%s: invalid remote socket", __func__); |
| 354 | return -1; |
| 355 | } |
| 356 | |
| 357 | FD_ZERO(&client_fds); |
| 358 | FD_SET(remote_fm_hal_fd, &client_fds); |
| 359 | |
| 360 | do { |
| 361 | ALOGI("%s: Step 1-FM-HAL SERVICE: Waiting for FM HAL cmd ", __func__); |
| 362 | n = select(remote_fm_hal_fd+1, &client_fds, NULL, NULL, NULL); |
| 363 | if(n < 0){ |
| 364 | ALOGE("Select: failed: %s", strerror(errno)); |
| 365 | break; |
| 366 | } |
| 367 | ALOGI("%s: Step 2-FM-HAL SERVICE: FM POWER CMD available for processing...\n", __func__); |
| 368 | if (FD_ISSET(remote_fm_hal_fd, &client_fds)) { |
| 369 | retval = handle_fmcommand_writes(remote_fm_hal_fd); |
| 370 | ALOGI("%s: handle_fmcommand_writes . %d", __func__, retval); |
| 371 | if(retval < 0) { |
| 372 | if (retval == -99) { |
| 373 | ALOGI("%s:End of wait loop", __func__); |
| 374 | break; |
| 375 | } |
| 376 | ALOGI("%s: handle_fmcommand_writes returns: %d: ", __func__, retval); |
| 377 | // break; |
| 378 | } |
| 379 | } |
| 380 | } while(1); |
| 381 | |
| 382 | service_cleanup(); |
| 383 | ALOGI("%s: FM turned off or power off failed .service kill itself", __func__); |
| 384 | close(remote_fm_hal_fd); |
| 385 | remote_fm_hal_fd = 0; |
| 386 | |
| 387 | ALOGI("%s: Exit: %d", __func__, retval); |
| 388 | return retval; |
| 389 | } |
| 390 | |