/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define __STDC_LIMIT_MACROS #include <stdint.h> #define RIL_SHLIB #include "telephony/ril.h" #include "RilSapSocket.h" #include "pb_decode.h" #include "pb_encode.h" #define LOG_TAG "RIL_UIM_SOCKET" #include <utils/Log.h> #include <arpa/inet.h> #include <errno.h> static RilSapSocket::RilSapSocketList *head = NULL; void ril_sap_on_request_complete ( RIL_Token t, RIL_Errno e, void *response, size_t responselen ); void ril_sap_on_unsolicited_response ( int unsolResponse, const void *data, size_t datalen ); extern "C" void RIL_requestTimedCallback (RIL_TimedCallback callback, void *param, const struct timeval *relativeTime); struct RIL_Env RilSapSocket::uimRilEnv = { .OnRequestComplete = RilSapSocket::sOnRequestComplete, .OnUnsolicitedResponse = RilSapSocket::sOnUnsolicitedResponse, .RequestTimedCallback = RIL_requestTimedCallback }; void RilSapSocket::sOnRequestComplete (RIL_Token t, RIL_Errno e, void *response, size_t responselen) { RilSapSocket *sap_socket; SapSocketRequest *request = (SapSocketRequest*) t; RLOGD("Socket id:%d", request->socketId); sap_socket = getSocketById(request->socketId); if (sap_socket) { sap_socket->onRequestComplete(t,e,response,responselen); } else { RLOGE("Invalid socket id"); if (request->curr->payload) { free(request->curr->payload); } free(request->curr); free(request); } } #if defined(ANDROID_MULTI_SIM) void RilSapSocket::sOnUnsolicitedResponse(int unsolResponse, const void *data, size_t datalen, RIL_SOCKET_ID socketId) { RilSapSocket *sap_socket = getSocketById(socketId); if (sap_socket) { sap_socket->onUnsolicitedResponse(unsolResponse, (void *)data, datalen); } } #else void RilSapSocket::sOnUnsolicitedResponse(int unsolResponse, const void *data, size_t datalen) { RilSapSocket *sap_socket = getSocketById(RIL_SOCKET_1); sap_socket->onUnsolicitedResponse(unsolResponse, (void *)data, datalen); } #endif void RilSapSocket::printList() { RilSapSocketList *current = head; RLOGD("Printing socket list"); while(NULL != current) { RLOGD("SocketName:%s",current->socket->name); RLOGD("Socket id:%d",current->socket->id); current = current->next; } } RilSapSocket *RilSapSocket::getSocketById(RIL_SOCKET_ID socketId) { RilSapSocket *sap_socket; RilSapSocketList *current = head; RLOGD("Entered getSocketById"); printList(); while(NULL != current) { if(socketId == current->socket->id) { sap_socket = current->socket; return sap_socket; } current = current->next; } return NULL; } void RilSapSocket::initSapSocket(const char *socketName, RIL_RadioFunctions *uimFuncs) { if (strcmp(socketName, "sap_uim_socket1") == 0) { if(!SocketExists(socketName)) { addSocketToList(socketName, RIL_SOCKET_1, uimFuncs); } } #if (SIM_COUNT >= 2) if (strcmp(socketName, "sap_uim_socket2") == 0) { if(!SocketExists(socketName)) { addSocketToList(socketName, RIL_SOCKET_2, uimFuncs); } } #endif #if (SIM_COUNT >= 3) if (strcmp(socketName, "sap_uim_socket3") == 0) { if(!SocketExists(socketName)) { addSocketToList(socketName, RIL_SOCKET_3, uimFuncs); } } #endif #if (SIM_COUNT >= 4) if (strcmp(socketName, "sap_uim_socket4") == 0) { if(!SocketExists(socketName)) { addSocketToList(socketName, RIL_SOCKET_4, uimFuncs); } } #endif } void RilSapSocket::addSocketToList(const char *socketName, RIL_SOCKET_ID socketid, RIL_RadioFunctions *uimFuncs) { RilSapSocket* socket = NULL; RilSapSocketList *current; if(!SocketExists(socketName)) { socket = new RilSapSocket(socketName, socketid, uimFuncs); RilSapSocketList* listItem = (RilSapSocketList*)malloc(sizeof(RilSapSocketList)); if (!listItem) { RLOGE("addSocketToList: OOM"); return; } listItem->socket = socket; listItem->next = NULL; RLOGD("Adding socket with id: %d", socket->id); if(NULL == head) { head = listItem; head->next = NULL; } else { current = head; while(NULL != current->next) { current = current->next; } current->next = listItem; } socket->socketInit(); } } bool RilSapSocket::SocketExists(const char *socketName) { RilSapSocketList* current = head; while(NULL != current) { if(strcmp(current->socket->name, socketName) == 0) { return true; } current = current->next; } return false; } void* RilSapSocket::processRequestsLoop(void) { RLOGI("UIM_SOCKET:Request loop started"); while(true) { SapSocketRequest *req = dispatchQueue.dequeue(); RLOGI("New request from the dispatch Queue"); if (req != NULL) { dispatchRequest(req->curr); free(req); } else { RLOGE("Fetched null buffer from queue!"); } } return NULL; } RilSapSocket::RilSapSocket(const char *socketName, RIL_SOCKET_ID socketId, RIL_RadioFunctions *inputUimFuncs): RilSocket(socketName, socketId) { if (inputUimFuncs) { uimFuncs = inputUimFuncs; } } #define BYTES_PER_LINE 16 #define NIBBLE_TO_HEX(n) ({ \ uint8_t __n = (uint8_t) n & 0x0f; \ __nibble >= 10 ? 'A' + __n - 10: '0' + __n; \ }) #define HEX_HIGH(b) ({ \ uint8_t __b = (uint8_t) b; \ uint8_t __nibble = (__b >> 4) & 0x0f; \ NIBBLE_TO_HEX(__nibble); \ }) #define HEX_LOW(b) ({ \ uint8_t __b = (uint8_t) b; \ uint8_t __nibble = __b & 0x0f; \ NIBBLE_TO_HEX(__nibble); \ }) void log_hex(const char *who, const uint8_t *buffer, int length) { char out[80]; int source = 0; int dest = 0; int dest_len = sizeof(out); int per_line = 0; do { dest += sprintf(out, "%8.8s [%8.8x] ", who, source); for(; source < length && dest_len - dest > 3 && per_line < BYTES_PER_LINE; source++, per_line ++) { out[dest++] = HEX_HIGH(buffer[source]); out[dest++] = HEX_LOW(buffer[source]); out[dest++] = ' '; } if (dest < dest_len && (per_line == BYTES_PER_LINE || source >= length)) { out[dest++] = 0; per_line = 0; dest = 0; RLOGD("%s\n", out); } } while(source < length && dest < dest_len); } void RilSapSocket::dispatchRequest(MsgHeader *req) { // SapSocketRequest will be deallocated in onRequestComplete() SapSocketRequest* currRequest=(SapSocketRequest*)malloc(sizeof(SapSocketRequest)); if (!currRequest) { RLOGE("dispatchRequest: OOM"); // Free MsgHeader allocated in pushRecord() free(req); return; } currRequest->token = req->token; currRequest->curr = req; currRequest->p_next = NULL; currRequest->socketId = id; pendingResponseQueue.enqueue(currRequest); if (uimFuncs) { RLOGI("[%d] > SAP REQUEST type: %d. id: %d. error: %d", req->token, req->type, req->id, req->error ); #if defined(ANDROID_MULTI_SIM) uimFuncs->onRequest(req->id, req->payload->bytes, req->payload->size, currRequest, id); #else uimFuncs->onRequest(req->id, req->payload->bytes, req->payload->size, currRequest); #endif } } void RilSapSocket::onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t response_len) { SapSocketRequest* request= (SapSocketRequest*)t; MsgHeader *hdr = request->curr; if (response && response_len > 0) { MsgHeader rsp; rsp.token = request->curr->token; rsp.type = MsgType_RESPONSE; rsp.id = request->curr->id; rsp.error = (Error)e; rsp.payload = (pb_bytes_array_t *)calloc(1, sizeof(pb_bytes_array_t) + response_len); if (!rsp.payload) { RLOGE("onRequestComplete: OOM"); } else { memcpy(rsp.payload->bytes, response, response_len); rsp.payload->size = response_len; RLOGE("Token:%d, MessageId:%d", hdr->token, hdr->id); sendResponse(&rsp); free(rsp.payload); } } // Deallocate SapSocketRequest if(!pendingResponseQueue.checkAndDequeue(hdr->id, hdr->token)) { RLOGE("Token:%d, MessageId:%d", hdr->token, hdr->id); RLOGE ("RilSapSocket::onRequestComplete: invalid Token or Message Id"); } // Deallocate MsgHeader free(hdr); } void RilSapSocket::sendResponse(MsgHeader* hdr) { size_t encoded_size = 0; uint32_t written_size; size_t buffer_size = 0; pb_ostream_t ostream; bool success = false; pthread_mutex_lock(&write_lock); if ((success = pb_get_encoded_size(&encoded_size, MsgHeader_fields, hdr)) && encoded_size <= INT32_MAX && commandFd != -1) { buffer_size = encoded_size + sizeof(uint32_t); uint8_t buffer[buffer_size]; written_size = htonl((uint32_t) encoded_size); ostream = pb_ostream_from_buffer(buffer, buffer_size); pb_write(&ostream, (uint8_t *)&written_size, sizeof(written_size)); success = pb_encode(&ostream, MsgHeader_fields, hdr); if (success) { RLOGD("Size: %d (0x%x) Size as written: 0x%x", encoded_size, encoded_size, written_size); log_hex("onRequestComplete", &buffer[sizeof(written_size)], encoded_size); RLOGI("[%d] < SAP RESPONSE type: %d. id: %d. error: %d", hdr->token, hdr->type, hdr->id,hdr->error ); if ( 0 != blockingWrite_helper(commandFd, buffer, buffer_size)) { RLOGE("Error %d while writing to fd", errno); } else { RLOGD("Write successful"); } } else { RLOGE("Error while encoding response of type %d id %d buffer_size: %d: %s.", hdr->type, hdr->id, buffer_size, PB_GET_ERROR(&ostream)); } } else { RLOGE("Not sending response type %d: encoded_size: %u. commandFd: %d. encoded size result: %d", hdr->type, encoded_size, commandFd, success); } pthread_mutex_unlock(&write_lock); } void RilSapSocket::onUnsolicitedResponse(int unsolResponse, void *data, size_t datalen) { if (data && datalen > 0) { pb_bytes_array_t *payload = (pb_bytes_array_t *)calloc(1, sizeof(pb_bytes_array_t) + datalen); if (!payload) { RLOGE("onUnsolicitedResponse: OOM"); return; } memcpy(payload->bytes, data, datalen); payload->size = datalen; MsgHeader rsp; rsp.payload = payload; rsp.type = MsgType_UNSOL_RESPONSE; rsp.id = (MsgId)unsolResponse; rsp.error = Error_RIL_E_SUCCESS; sendResponse(&rsp); free(payload); } } void RilSapSocket::pushRecord(void *p_record, size_t recordlen) { pb_istream_t stream = pb_istream_from_buffer((uint8_t *)p_record, recordlen); // MsgHeader will be deallocated in onRequestComplete() MsgHeader *reqHeader = (MsgHeader *)malloc(sizeof (MsgHeader)); if (!reqHeader) { RLOGE("pushRecord: OOM"); return; } memset(reqHeader, 0, sizeof(MsgHeader)); log_hex("BtSapTest-Payload", (const uint8_t*)p_record, recordlen); if (!pb_decode(&stream, MsgHeader_fields, reqHeader) ) { RLOGE("Error decoding protobuf buffer : %s", PB_GET_ERROR(&stream)); free(reqHeader); } else { // SapSocketRequest will be deallocated in processRequestsLoop() SapSocketRequest *recv = (SapSocketRequest*)malloc(sizeof(SapSocketRequest)); if (!recv) { RLOGE("pushRecord: OOM"); free(reqHeader); return; } recv->token = reqHeader->token; recv->curr = reqHeader; recv->socketId = id; dispatchQueue.enqueue(recv); } } void RilSapSocket::sendDisconnect() { size_t encoded_size = 0; uint32_t written_size; size_t buffer_size = 0; pb_ostream_t ostream; bool success = false; RIL_SIM_SAP_DISCONNECT_REQ disconnectReq; if ((success = pb_get_encoded_size(&encoded_size, RIL_SIM_SAP_DISCONNECT_REQ_fields, &disconnectReq)) && encoded_size <= INT32_MAX) { buffer_size = encoded_size + sizeof(uint32_t); uint8_t buffer[buffer_size]; written_size = htonl((uint32_t) encoded_size); ostream = pb_ostream_from_buffer(buffer, buffer_size); pb_write(&ostream, (uint8_t *)&written_size, sizeof(written_size)); success = pb_encode(&ostream, RIL_SIM_SAP_DISCONNECT_REQ_fields, buffer); if(success) { // Buffer will be deallocated in sOnRequestComplete() pb_bytes_array_t *payload = (pb_bytes_array_t *)calloc(1, sizeof(pb_bytes_array_t) + written_size); if (!payload) { RLOGE("sendDisconnect: OOM"); return; } memcpy(payload->bytes, buffer, written_size); payload->size = written_size; // MsgHeader will be deallocated in sOnRequestComplete() MsgHeader *hdr = (MsgHeader *)malloc(sizeof(MsgHeader)); if (!hdr) { RLOGE("sendDisconnect: OOM"); free(payload); return; } hdr->payload = payload; hdr->type = MsgType_REQUEST; hdr->id = MsgId_RIL_SIM_SAP_DISCONNECT; hdr->error = Error_RIL_E_SUCCESS; dispatchDisconnect(hdr); } else { RLOGE("Encode failed in send disconnect!"); } } } void RilSapSocket::dispatchDisconnect(MsgHeader *req) { // SapSocketRequest will be deallocated in sOnRequestComplete() SapSocketRequest* currRequest=(SapSocketRequest*)malloc(sizeof(SapSocketRequest)); if (!currRequest) { RLOGE("dispatchDisconnect: OOM"); // Free memory allocated in sendDisconnect free(req->payload); free(req); return; } currRequest->token = -1; currRequest->curr = req; currRequest->p_next = NULL; currRequest->socketId = (RIL_SOCKET_ID)99; RLOGD("Sending disconnect on command close!"); #if defined(ANDROID_MULTI_SIM) uimFuncs->onRequest(req->id, req->payload->bytes, req->payload->size, currRequest, id); #else uimFuncs->onRequest(req->id, req->payload->bytes, req->payload->size, currRequest); #endif } void RilSapSocket::onCommandsSocketClosed() { sendDisconnect(); RLOGE("Socket command closed"); }