#include "secril-shim.h" /* A copy of the original RIL function table. */ static const RIL_RadioFunctions *origRilFunctions; /* A copy of the ril environment passed to RIL_Init. */ static const struct RIL_Env *rilEnv; static void onRequestShim(int request, void *data, size_t datalen, RIL_Token t) { switch (request) { /* Necessary; RILJ may fake this for us if we reply not supported, but we can just implement it. */ case RIL_REQUEST_GET_RADIO_CAPABILITY: ; /* lol C standard */ RIL_RadioCapability rc[1] = { { /* rc[0] */ RIL_RADIO_CAPABILITY_VERSION, /* version */ 0, /* session */ RC_PHASE_CONFIGURED, /* phase */ RAF_GSM | RAF_GPRS | RAF_EDGE | RAF_HSUPA | RAF_HSDPA | RAF_HSPA | RAF_HSPAP | RAF_UMTS, /* rat */ { /* logicalModemUuid */ 0, }, RC_STATUS_SUCCESS /* status */ } }; RLOGW("%s: got request %s: replied with our implementation!\n", __func__, requestToString(request)); rilEnv->OnRequestComplete(t, RIL_E_SUCCESS, rc, sizeof(rc)); return; /* The following requests were introduced post-4.3. */ case RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC: case RIL_REQUEST_SIM_OPEN_CHANNEL: /* !!! */ case RIL_REQUEST_SIM_CLOSE_CHANNEL: case RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL: case RIL_REQUEST_NV_READ_ITEM: case RIL_REQUEST_NV_WRITE_ITEM: case RIL_REQUEST_NV_WRITE_CDMA_PRL: case RIL_REQUEST_NV_RESET_CONFIG: case RIL_REQUEST_SET_UICC_SUBSCRIPTION: case RIL_REQUEST_ALLOW_DATA: case RIL_REQUEST_GET_HARDWARE_CONFIG: case RIL_REQUEST_SIM_AUTHENTICATION: case RIL_REQUEST_GET_DC_RT_INFO: case RIL_REQUEST_SET_DC_RT_INFO_RATE: case RIL_REQUEST_SET_DATA_PROFILE: case RIL_REQUEST_SHUTDOWN: /* TODO: Is there something we can do for RIL_REQUEST_SHUTDOWN ? */ case RIL_REQUEST_SET_RADIO_CAPABILITY: case RIL_REQUEST_START_LCE: case RIL_REQUEST_STOP_LCE: case RIL_REQUEST_PULL_LCEDATA: RLOGW("%s: got request %s: replied with REQUEST_NOT_SUPPPORTED.\n", __func__, requestToString(request)); rilEnv->OnRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0); return; } RLOGD("%s: got request %s: forwarded to RIL.\n", __func__, requestToString(request)); origRilFunctions->onRequest(request, data, datalen, t); } static void onCompleteQueryAvailableNetworks(RIL_Token t, RIL_Errno e, void *response, size_t responselen) { /* Response is a char **, pointing to an array of char *'s */ size_t numStrings = responselen / sizeof(char *); size_t numNeededStrings = numStrings - (numStrings / 5); size_t newResponseLen = numNeededStrings * sizeof(char *); void *newResponse = malloc(newResponseLen); /* Remove every 5th string (qan element) */ char **p_cur = (char **) response; char **p_new = (char **) newResponse; size_t i, j; for (i = 0, j = 0; i < numStrings; ++i) { if ((i + 1) % 5 != 0) { p_new[j] = p_cur[i]; ++j; } } /* Send the fixed response to libril */ rilEnv->OnRequestComplete(t, e, newResponse, newResponseLen); free(newResponse); } static void onRequestCompleteShim(RIL_Token t, RIL_Errno e, void *response, size_t responselen) { int request; RequestInfo *pRI; pRI = (RequestInfo *)t; /* If pRI is null, this entire function is useless. */ if (pRI == NULL) goto null_token_exit; request = pRI->pCI->requestNumber; switch (request) { case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS: /* Remove the extra (unused) element from the operator info, freaking out the framework. * Formerly, this is know as the mQANElements override. */ if (response != NULL && responselen != 0 && (responselen % sizeof(char *) == 0)) { onCompleteQueryAvailableNetworks(t, e, response, responselen); return; } break; } RLOGD("%s: got request %s: forwarded to libril.\n", __func__, requestToString(request)); null_token_exit: rilEnv->OnRequestComplete(t, e, response, responselen); } const RIL_RadioFunctions* RIL_Init(const struct RIL_Env *env, int argc, char **argv) { RIL_RadioFunctions const* (*origRilInit)(const struct RIL_Env *env, int argc, char **argv); static RIL_RadioFunctions shimmedFunctions; static struct RIL_Env shimmedEnv; void *origRil; /* Shim the RIL_Env passed to the real RIL, saving a copy of the original */ rilEnv = env; shimmedEnv = *env; shimmedEnv.OnRequestComplete = onRequestCompleteShim; /* Open and Init the original RIL. */ origRil = dlopen(RIL_LIB_PATH, RTLD_LOCAL); if (CC_UNLIKELY(!origRil)) { RLOGE("%s: failed to load '" RIL_LIB_PATH "': %s\n", __func__, dlerror()); return NULL; } origRilInit = dlsym(origRil, "RIL_Init"); if (CC_UNLIKELY(!origRilInit)) { RLOGE("%s: couldn't find original RIL_Init!\n", __func__); goto fail_after_dlopen; } origRilFunctions = origRilInit(&shimmedEnv, argc, argv); if (CC_UNLIKELY(!origRilFunctions)) { RLOGE("%s: the original RIL_Init derped.\n", __func__); goto fail_after_dlopen; } /* Shim functions as needed. */ shimmedFunctions = *origRilFunctions; shimmedFunctions.onRequest = onRequestShim; return &shimmedFunctions; fail_after_dlopen: dlclose(origRil); return NULL; }