diff --git a/include/telephony/record_stream.h b/include/telephony/record_stream.h new file mode 100644 index 0000000..7a89ae4 --- /dev/null +++ b/include/telephony/record_stream.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2006 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. + */ + +/* + * A simple utility for reading fixed records out of a stream fd + */ + +#ifndef _LIBRIL_RECORD_STREAM_H +#define _LIBRIL_RECORD_STREAM_H + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct RecordStream RecordStream; + +extern RecordStream *record_stream_new(int fd, size_t maxRecordLen); +extern void record_stream_free(RecordStream *p_rs); + +extern int record_stream_get_next (RecordStream *p_rs, void ** p_outRecord, + size_t *p_outRecordLen); + +#ifdef __cplusplus +} +#endif + + +#endif /*_LIBRIL_RECORD_STREAM_H*/ + diff --git a/include/telephony/ril.h b/include/telephony/ril.h index 5b54efe..c9f9ff6 100644 --- a/include/telephony/ril.h +++ b/include/telephony/ril.h @@ -19,6 +19,7 @@ #include #include +#include #ifndef FEATURE_UNIT_TEST #include #endif /* !FEATURE_UNIT_TEST */ @@ -27,7 +28,7 @@ extern "C" { #endif -#define RIL_VERSION 8 /* Current version */ +#define RIL_VERSION 9 /* Current version */ #ifdef LEGACY_RIL #define RIL_VERSION_MIN 2 /* Minimum RIL_VERSION supported */ #else @@ -125,7 +126,8 @@ typedef enum { PREF_NET_TYPE_LTE_CDMA_EVDO = 8, /* LTE, CDMA and EvDo */ PREF_NET_TYPE_LTE_GSM_WCDMA = 9, /* LTE, GSM/WCDMA */ PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA = 10, /* LTE, CDMA, EvDo, GSM/WCDMA */ - PREF_NET_TYPE_LTE_ONLY = 11 /* LTE only */ + PREF_NET_TYPE_LTE_ONLY = 11, /* LTE only */ + PREF_NET_TYPE_LTE_WCDMA = 12 /* LTE/WCDMA */ } RIL_PreferredNetworkType; /* Source for cdma subscription */ @@ -239,6 +241,28 @@ typedef struct { to point connections. */ } RIL_Data_Call_Response_v6; +typedef enum { + RADIO_TECH_3GPP = 1, /* 3GPP Technologies - GSM, WCDMA */ + RADIO_TECH_3GPP2 = 2 /* 3GPP2 Technologies - CDMA */ +} RIL_RadioTechnologyFamily; + +typedef struct { + RIL_RadioTechnologyFamily tech; + unsigned char retry; /* 0 == not retry, nonzero == retry */ + int messageRef; /* Valid field if retry is set to nonzero. + Contains messageRef from RIL_SMS_Response + corresponding to failed MO SMS. + */ + + union { + /* Valid field if tech is RADIO_TECH_3GPP2. See RIL_REQUEST_CDMA_SEND_SMS */ + RIL_CDMA_SMS_Message* cdmaMessage; + + /* Valid field if tech is RADIO_TECH_3GPP. See RIL_REQUEST_SEND_SMS */ + char** gsmMessage; + } message; +} RIL_IMS_SMS_Message; + typedef struct { int messageRef; /* TP-Message-Reference for GSM, and BearerData MessageId for CDMA @@ -405,7 +429,7 @@ typedef enum { PDP_FAIL_DATA_REGISTRATION_FAIL = -2, /* reasons for data call drop - network/modem disconnect */ - PDP_FAIL_SIGNAL_LOST = -3, /* no retry */ + PDP_FAIL_SIGNAL_LOST = -3, PDP_FAIL_PREF_RADIO_TECH_CHANGED = -4,/* preferred technology has changed, should retry with parameters appropriate for new technology */ PDP_FAIL_RADIO_POWER_OFF = -5, /* data call was disconnected because radio was resetting, @@ -3490,6 +3514,64 @@ typedef struct { */ #define RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE 110 +/** + * RIL_REQUEST_SET_INITIAL_ATTACH_APN + * + * Set an apn to initial attach network + * "response" is NULL + * + * Valid errors: + * SUCCESS + * RADIO_NOT_AVAILABLE (radio resetting) + * GENERIC_FAILURE + * SUBSCRIPTION_NOT_AVAILABLE + */ +#define RIL_REQUEST_SET_INITIAL_ATTACH_APN 111 + +/** + * RIL_REQUEST_IMS_REGISTRATION_STATE + * + * Request current IMS registration state + * + * "data" is NULL + * + * "response" is int * + * ((int *)response)[0] is registration state: + * 0 - Not registered + * 1 - Registered + * ((int *)response)[1] is bitmap of the supported services: + * & 0x1 - SMS supported + * + * If IMS is registered and supports SMS, then ((int *) response)[2] + * must follow with IMS SMS format: + * + * ((int *) response)[2] is of type const RIL_IMS_SMS_Format + */ +#define RIL_REQUEST_IMS_REGISTRATION_STATE 112 + +/** + * RIL_REQUEST_IMS_SEND_SMS + * + * Send a SMS message over IMS + * + * "data" is const RIL_IMS_SMS_Message * + * + * "response" is a const RIL_SMS_Response * + * + * Based on the return error, caller decides to resend if sending sms + * fails. SMS_SEND_FAIL_RETRY means retry, and other errors means no retry. + * In case of retry, data is encoded based on Voice Technology available. + * + * Valid errors: + * SUCCESS + * RADIO_NOT_AVAILABLE + * SMS_SEND_FAIL_RETRY + * FDN_CHECK_FAILURE + * GENERIC_FAILURE + * + */ +#define RIL_REQUEST_IMS_SEND_SMS 113 + /***********************************************************************/ @@ -3980,6 +4062,25 @@ typedef struct { */ #define RIL_UNSOL_CELL_INFO_LIST 1036 +/* + * RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED + * + * Called when IMS registration state has changed + * + * "data" is int * + * ((int *)response)[0] is registration state: + * 0 - Not registered + * 1 - Registered + * ((int *)response)[1] is bitmap of the services supported: + * & 0x1 - SMS supported + * + * If IMS is registered and supports SMS, then ((int *) response)[2] + * must follow with IMS SMS format: + * + * ((int *) response)[2] is of type const RIL_IMS_SMS_Format + */ +#define RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED 1037 + /***********************************************************************/ @@ -4048,6 +4149,14 @@ typedef struct { RIL_GetVersion getVersion; } RIL_RadioFunctions; +typedef struct { + char *apn; + char *protocol; + int authtype; + char *username; + char *password; +} RIL_InitialAttachApn; + #ifdef RIL_SHLIB struct RIL_Env { /** diff --git a/libril/Android.mk b/libril/Android.mk index 7c568c3..0e8dfb5 100644 --- a/libril/Android.mk +++ b/libril/Android.mk @@ -14,7 +14,8 @@ LOCAL_SHARED_LIBRARIES := \ libutils \ libbinder \ libcutils \ - libhardware_legacy + libhardware_legacy \ + librilutils LOCAL_CFLAGS := ifdef BOARD_USE_NEW_LIBRIL_HTC @@ -51,7 +52,8 @@ LOCAL_SRC_FILES:= \ LOCAL_STATIC_LIBRARIES := \ libutils_static \ - libcutils + libcutils \ + librilutils_static LOCAL_CFLAGS := diff --git a/libril/ril.cpp b/libril/ril.cpp index e398cf6..2b4292e 100644 --- a/libril/ril.cpp +++ b/libril/ril.cpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include @@ -204,9 +204,13 @@ static void dispatchRaw(Parcel& p, RequestInfo *pRI); static void dispatchSmsWrite (Parcel &p, RequestInfo *pRI); static void dispatchDataCall (Parcel& p, RequestInfo *pRI); static void dispatchVoiceRadioTech (Parcel& p, RequestInfo *pRI); +static void dispatchSetInitialAttachApn (Parcel& p, RequestInfo *pRI); static void dispatchCdmaSubscriptionSource (Parcel& p, RequestInfo *pRI); static void dispatchCdmaSms(Parcel &p, RequestInfo *pRI); +static void dispatchImsSms(Parcel &p, RequestInfo *pRI); +static void dispatchImsCdmaSms(Parcel &p, RequestInfo *pRI, uint8_t retry, int32_t messageRef); +static void dispatchImsGsmSms(Parcel &p, RequestInfo *pRI, uint8_t retry, int32_t messageRef); static void dispatchCdmaSmsAck(Parcel &p, RequestInfo *pRI); static void dispatchGsmBrSmsCnf(Parcel &p, RequestInfo *pRI); static void dispatchCdmaBrSmsCnf(Parcel &p, RequestInfo *pRI); @@ -880,9 +884,8 @@ dispatchRaw(Parcel &p, RequestInfo *pRI) { return; } -static void -dispatchCdmaSms(Parcel &p, RequestInfo *pRI) { - RIL_CDMA_SMS_Message rcsm; +static status_t +constructCdmaSms(Parcel &p, RequestInfo *pRI, RIL_CDMA_SMS_Message& rcsm) { int32_t t; uint8_t ut; status_t status; @@ -946,7 +949,7 @@ dispatchCdmaSms(Parcel &p, RequestInfo *pRI) { } if (status != NO_ERROR) { - goto invalid; + return status; } startRequest; @@ -958,6 +961,18 @@ dispatchCdmaSms(Parcel &p, RequestInfo *pRI) { printRequest(pRI->token, pRI->pCI->requestNumber); + return status; +} + +static void +dispatchCdmaSms(Parcel &p, RequestInfo *pRI) { + RIL_CDMA_SMS_Message rcsm; + + ALOGD("dispatchCdmaSms"); + if (NO_ERROR != constructCdmaSms(p, pRI, rcsm)) { + goto invalid; + } + s_callbacks.onRequest(pRI->pCI->requestNumber, &rcsm, sizeof(rcsm),pRI); #ifdef MEMSET_FREED @@ -971,6 +986,149 @@ dispatchCdmaSms(Parcel &p, RequestInfo *pRI) { return; } +static void +dispatchImsCdmaSms(Parcel &p, RequestInfo *pRI, uint8_t retry, int32_t messageRef) { + RIL_IMS_SMS_Message rism; + RIL_CDMA_SMS_Message rcsm; + + ALOGD("dispatchImsCdmaSms: retry=%d, messageRef=%d", retry, messageRef); + + if (NO_ERROR != constructCdmaSms(p, pRI, rcsm)) { + goto invalid; + } + memset(&rism, 0, sizeof(rism)); + rism.tech = RADIO_TECH_3GPP2; + rism.retry = retry; + rism.messageRef = messageRef; + rism.message.cdmaMessage = &rcsm; + + s_callbacks.onRequest(pRI->pCI->requestNumber, &rism, + sizeof(RIL_RadioTechnologyFamily)+sizeof(uint8_t)+sizeof(int32_t) + +sizeof(rcsm),pRI); + +#ifdef MEMSET_FREED + memset(&rcsm, 0, sizeof(rcsm)); + memset(&rism, 0, sizeof(rism)); +#endif + + return; + +invalid: + invalidCommandBlock(pRI); + return; +} + +static void +dispatchImsGsmSms(Parcel &p, RequestInfo *pRI, uint8_t retry, int32_t messageRef) { + RIL_IMS_SMS_Message rism; + int32_t countStrings; + status_t status; + size_t datalen; + char **pStrings; + ALOGD("dispatchImsGsmSms: retry=%d, messageRef=%d", retry, messageRef); + + status = p.readInt32 (&countStrings); + + if (status != NO_ERROR) { + goto invalid; + } + + memset(&rism, 0, sizeof(rism)); + rism.tech = RADIO_TECH_3GPP; + rism.retry = retry; + rism.messageRef = messageRef; + + startRequest; + appendPrintBuf("%sformat=%d,", printBuf, rism.format); + if (countStrings == 0) { + // just some non-null pointer + pStrings = (char **)alloca(sizeof(char *)); + datalen = 0; + } else if (((int)countStrings) == -1) { + pStrings = NULL; + datalen = 0; + } else { + datalen = sizeof(char *) * countStrings; + + pStrings = (char **)alloca(datalen); + + for (int i = 0 ; i < countStrings ; i++) { + pStrings[i] = strdupReadString(p); + appendPrintBuf("%s%s,", printBuf, pStrings[i]); + } + } + removeLastChar; + closeRequest; + printRequest(pRI->token, pRI->pCI->requestNumber); + + rism.message.gsmMessage = pStrings; + s_callbacks.onRequest(pRI->pCI->requestNumber, &rism, + sizeof(RIL_RadioTechnologyFamily)+sizeof(uint8_t)+sizeof(int32_t) + +datalen, pRI); + + if (pStrings != NULL) { + for (int i = 0 ; i < countStrings ; i++) { +#ifdef MEMSET_FREED + memsetString (pStrings[i]); +#endif + free(pStrings[i]); + } + +#ifdef MEMSET_FREED + memset(pStrings, 0, datalen); +#endif + } + +#ifdef MEMSET_FREED + memset(&rism, 0, sizeof(rism)); +#endif + return; +invalid: + ALOGE("dispatchImsGsmSms invalid block"); + invalidCommandBlock(pRI); + return; +} + +static void +dispatchImsSms(Parcel &p, RequestInfo *pRI) { + int32_t t; + status_t status = p.readInt32(&t); + RIL_RadioTechnologyFamily format; + uint8_t retry; + int32_t messageRef; + + ALOGD("dispatchImsSms"); + if (status != NO_ERROR) { + goto invalid; + } + format = (RIL_RadioTechnologyFamily) t; + + // read retry field + status = p.read(&retry,sizeof(retry)); + if (status != NO_ERROR) { + goto invalid; + } + // read messageRef field + status = p.read(&messageRef,sizeof(messageRef)); + if (status != NO_ERROR) { + goto invalid; + } + + if (RADIO_TECH_3GPP == format) { + dispatchImsGsmSms(p, pRI, retry, messageRef); + } else if (RADIO_TECH_3GPP2 == format) { + dispatchImsCdmaSms(p, pRI, retry, messageRef); + } else { + ALOGE("requestImsSendSMS invalid format value =%d", format); + } + + return; + +invalid: + invalidCommandBlock(pRI); + return; +} + static void dispatchCdmaSmsAck(Parcel &p, RequestInfo *pRI) { RIL_CDMA_SMS_Ack rcsa; @@ -1307,6 +1465,56 @@ static void dispatchCdmaSubscriptionSource(Parcel& p, RequestInfo *pRI) { RIL_onRequestComplete(pRI, RIL_E_SUCCESS, &cdmaSubscriptionSource, sizeof(int)); } +static void dispatchSetInitialAttachApn(Parcel &p, RequestInfo *pRI) +{ + RIL_InitialAttachApn pf; + int32_t t; + status_t status; + + memset(&pf, 0, sizeof(pf)); + + pf.apn = strdupReadString(p); + pf.protocol = strdupReadString(p); + + status = p.readInt32(&t); + pf.authtype = (int) t; + + pf.username = strdupReadString(p); + pf.password = strdupReadString(p); + + startRequest; + appendPrintBuf("%sapn=%s, protocol=%s, auth_type=%d, username=%s, password=%s", + printBuf, pf.apn, pf.protocol, pf.auth_type, pf.username, pf.password); + closeRequest; + printRequest(pRI->token, pRI->pCI->requestNumber); + + if (status != NO_ERROR) { + goto invalid; + } + s_callbacks.onRequest(pRI->pCI->requestNumber, &pf, sizeof(pf), pRI); + +#ifdef MEMSET_FREED + memsetString(pf.apn); + memsetString(pf.protocol); + memsetString(pf.username); + memsetString(pf.password); +#endif + + free(pf.apn); + free(pf.protocol); + free(pf.username); + free(pf.password); + +#ifdef MEMSET_FREED + memset(&pf, 0, sizeof(pf)); +#endif + + return; +invalid: + invalidCommandBlock(pRI); + return; +} + static int blockingWrite(int fd, const void *buffer, size_t len) { size_t writeOffset = 0; @@ -3635,6 +3843,9 @@ requestToString(int request) { case RIL_REQUEST_GET_CELL_INFO_LIST: return"GET_CELL_INFO_LIST"; case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE: return"SET_UNSOL_CELL_INFO_LIST_RATE"; #endif + case RIL_REQUEST_SET_INITIAL_ATTACH_APN: return "RIL_REQUEST_SET_INITIAL_ATTACH_APN"; + case RIL_REQUEST_IMS_REGISTRATION_STATE: return "IMS_REGISTRATION_STATE"; + case RIL_REQUEST_IMS_SEND_SMS: return "IMS_SEND_SMS"; case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: return "UNSOL_RESPONSE_RADIO_STATE_CHANGED"; case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: return "UNSOL_RESPONSE_CALL_STATE_CHANGED"; case RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED: return "UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED"; @@ -3673,6 +3884,7 @@ requestToString(int request) { #ifndef RIL_NO_CELL_INFO_LIST case RIL_UNSOL_CELL_INFO_LIST: return "UNSOL_CELL_INFO_LIST"; #endif + case RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED: return "RESPONSE_IMS_NETWORK_STATE_CHANGED"; default: return ""; } } diff --git a/libril/ril_commands.h b/libril/ril_commands.h index ccf3efb..4d026c3 100644 --- a/libril/ril_commands.h +++ b/libril/ril_commands.h @@ -127,3 +127,6 @@ {RIL_REQUEST_GET_CELL_INFO_LIST, dispatchVoid, responseCellInfoList}, {RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE, dispatchInts, responseVoid}, #endif + {RIL_REQUEST_SET_INITIAL_ATTACH_APN, dispatchSetInitialAttachApn, responseVoid}, + {RIL_REQUEST_IMS_REGISTRATION_STATE, dispatchVoid, responseInts}, + {RIL_REQUEST_IMS_SEND_SMS, dispatchImsSms, responseSMS}, diff --git a/libril/ril_unsol_commands.h b/libril/ril_unsol_commands.h index 55dac19..ad6411e 100644 --- a/libril/ril_unsol_commands.h +++ b/libril/ril_unsol_commands.h @@ -53,3 +53,4 @@ #ifndef RIL_NO_CELL_INFO_LIST {RIL_UNSOL_CELL_INFO_LIST, responseCellInfoList, WAKE_PARTIAL}, #endif + {RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED, responseVoid, WAKE_PARTIAL}, diff --git a/librilutils/Android.mk b/librilutils/Android.mk index a959202..a50e374 100644 --- a/librilutils/Android.mk +++ b/librilutils/Android.mk @@ -4,7 +4,8 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ - librilutils.c + librilutils.c \ + record_stream.c LOCAL_CFLAGS := @@ -20,7 +21,8 @@ include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ - librilutils.c + librilutils.c \ + record_stream.c LOCAL_STATIC_LIBRARIES := diff --git a/librilutils/record_stream.c b/librilutils/record_stream.c new file mode 100644 index 0000000..558d179 --- /dev/null +++ b/librilutils/record_stream.c @@ -0,0 +1,186 @@ +/* +** +** Copyright 2006, 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. +*/ + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_WINSOCK +#include /* for ntohl */ +#else +#include +#endif + +#define HEADER_SIZE 4 + +struct RecordStream { + int fd; + size_t maxRecordLen; + + unsigned char *buffer; + + unsigned char *unconsumed; + unsigned char *read_end; + unsigned char *buffer_end; +}; + + +extern RecordStream *record_stream_new(int fd, size_t maxRecordLen) +{ + RecordStream *ret; + + assert (maxRecordLen <= 0xffff); + + ret = (RecordStream *)calloc(1, sizeof(RecordStream)); + + ret->fd = fd; + ret->maxRecordLen = maxRecordLen; + ret->buffer = (unsigned char *)malloc (maxRecordLen + HEADER_SIZE); + + ret->unconsumed = ret->buffer; + ret->read_end = ret->buffer; + ret->buffer_end = ret->buffer + maxRecordLen + HEADER_SIZE; + + return ret; +} + + +extern void record_stream_free(RecordStream *rs) +{ + free(rs->buffer); + free(rs); +} + + +/* returns NULL; if there isn't a full record in the buffer */ +static unsigned char * getEndOfRecord (unsigned char *p_begin, + unsigned char *p_end) +{ + size_t len; + unsigned char * p_ret; + + if (p_end < p_begin + HEADER_SIZE) { + return NULL; + } + + //First four bytes are length + len = ntohl(*((uint32_t *)p_begin)); + + p_ret = p_begin + HEADER_SIZE + len; + + if (p_end < p_ret) { + return NULL; + } + + return p_ret; +} + +static void *getNextRecord (RecordStream *p_rs, size_t *p_outRecordLen) +{ + unsigned char *record_start, *record_end; + + record_end = getEndOfRecord (p_rs->unconsumed, p_rs->read_end); + + if (record_end != NULL) { + /* one full line in the buffer */ + record_start = p_rs->unconsumed + HEADER_SIZE; + p_rs->unconsumed = record_end; + + *p_outRecordLen = record_end - record_start; + + return record_start; + } + + return NULL; +} + +/** + * Reads the next record from stream fd + * Records are prefixed by a 16-bit big endian length value + * Records may not be larger than maxRecordLen + * + * Doesn't guard against EINTR + * + * p_outRecord and p_outRecordLen may not be NULL + * + * Return 0 on success, -1 on fail + * Returns 0 with *p_outRecord set to NULL on end of stream + * Returns -1 / errno = EAGAIN if it needs to read again + */ +int record_stream_get_next (RecordStream *p_rs, void ** p_outRecord, + size_t *p_outRecordLen) +{ + void *ret; + + ssize_t countRead; + + /* is there one record already in the buffer? */ + ret = getNextRecord (p_rs, p_outRecordLen); + + if (ret != NULL) { + *p_outRecord = ret; + return 0; + } + + // if the buffer is full and we don't have a full record + if (p_rs->unconsumed == p_rs->buffer + && p_rs->read_end == p_rs->buffer_end + ) { + // this should never happen + //ALOGE("max record length exceeded\n"); + assert (0); + errno = EFBIG; + return -1; + } + + if (p_rs->unconsumed != p_rs->buffer) { + // move remainder to the beginning of the buffer + size_t toMove; + + toMove = p_rs->read_end - p_rs->unconsumed; + if (toMove) { + memmove(p_rs->buffer, p_rs->unconsumed, toMove); + } + + p_rs->read_end = p_rs->buffer + toMove; + p_rs->unconsumed = p_rs->buffer; + } + + countRead = read (p_rs->fd, p_rs->read_end, p_rs->buffer_end - p_rs->read_end); + + if (countRead <= 0) { + /* note: end-of-stream drops through here too */ + *p_outRecord = NULL; + return countRead; + } + + p_rs->read_end += countRead; + + ret = getNextRecord (p_rs, p_outRecordLen); + + if (ret == NULL) { + /* not enough of a buffer to for a whole command */ + errno = EAGAIN; + return -1; + } + + *p_outRecord = ret; + return 0; +} diff --git a/reference-ril/reference-ril.c b/reference-ril/reference-ril.c index e8529cb..097ca92 100644 --- a/reference-ril/reference-ril.c +++ b/reference-ril/reference-ril.c @@ -211,6 +211,14 @@ static const struct timeval TIMEVAL_SIMPOLL = {1,0}; static const struct timeval TIMEVAL_CALLSTATEPOLL = {0,500000}; static const struct timeval TIMEVAL_0 = {0,0}; +static int s_ims_registered = 0; // 0==unregistered +static int s_ims_services = 1; // & 0x1 == sms over ims supported +static int s_ims_format = 1; // FORMAT_3GPP(1) vs FORMAT_3GPP2(2); +static int s_ims_cause_retry = 0; // 1==causes sms over ims to temp fail +static int s_ims_cause_perm_failure = 0; // 1==causes sms over ims to permanent fail +static int s_ims_gsm_retry = 0; // 1==causes sms over gsm to temp fail +static int s_ims_gsm_fail = 0; // 1==causes sms over gsm to permanent fail + #ifdef WORKAROUND_ERRONEOUS_ANSWER // Max number of times we'll try to repoll when we think // we have a AT+CLCC race condition @@ -1501,12 +1509,14 @@ static void requestCdmaSendSMS(void *data, size_t datalen, RIL_Token t) // But it is not implemented yet. memset(&response, 0, sizeof(response)); + response.messageRef = 1; RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response)); return; error: // Cdma Send SMS will always cause send retry error. - RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, NULL, 0); + response.messageRef = -1; + RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response)); } static void requestSendSMS(void *data, size_t datalen, RIL_Token t) @@ -1519,6 +1529,12 @@ static void requestSendSMS(void *data, size_t datalen, RIL_Token t) RIL_SMS_Response response; ATResponse *p_response = NULL; + memset(&response, 0, sizeof(response)); + RLOGD("requestSendSMS datalen =%d", datalen); + + if (s_ims_gsm_fail != 0) goto error; + if (s_ims_gsm_retry != 0) goto error2; + smsc = ((const char **)data)[0]; pdu = ((const char **)data)[1]; @@ -1536,17 +1552,68 @@ static void requestSendSMS(void *data, size_t datalen, RIL_Token t) if (err != 0 || p_response->success == 0) goto error; - memset(&response, 0, sizeof(response)); - /* FIXME fill in messageRef and ackPDU */ - + response.messageRef = 1; RIL_onRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response)); at_response_free(p_response); return; error: - RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); + response.messageRef = -2; + RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, &response, sizeof(response)); + at_response_free(p_response); + return; +error2: + // send retry error. + response.messageRef = -1; + RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response)); at_response_free(p_response); + return; + } + +static void requestImsSendSMS(void *data, size_t datalen, RIL_Token t) +{ + RIL_IMS_SMS_Message *p_args; + RIL_SMS_Response response; + + memset(&response, 0, sizeof(response)); + + RLOGD("requestImsSendSMS: datalen=%d, " + "registered=%d, service=%d, format=%d, ims_perm_fail=%d, " + "ims_retry=%d, gsm_fail=%d, gsm_retry=%d", + datalen, s_ims_registered, s_ims_services, s_ims_format, + s_ims_cause_perm_failure, s_ims_cause_retry, s_ims_gsm_fail, + s_ims_gsm_retry); + + // figure out if this is gsm/cdma format + // then route it to requestSendSMS vs requestCdmaSendSMS respectively + p_args = (RIL_IMS_SMS_Message *)data; + + if (0 != s_ims_cause_perm_failure ) goto error; + + // want to fail over ims and this is first request over ims + if (0 != s_ims_cause_retry && 0 == p_args->retry) goto error2; + + if (RADIO_TECH_3GPP == p_args->tech) { + return requestSendSMS(p_args->message.gsmMessage, + datalen - sizeof(RIL_RadioTechnologyFamily), + t); + } else if (RADIO_TECH_3GPP2 == p_args->tech) { + return requestCdmaSendSMS(p_args->message.cdmaMessage, + datalen - sizeof(RIL_RadioTechnologyFamily), + t); + } else { + RLOGE("requestImsSendSMS invalid format value =%d", p_args->tech); + } + +error: + response.messageRef = -2; + RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, &response, sizeof(response)); + return; + +error2: + response.messageRef = -1; + RIL_onRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response)); } static void requestSetupDataCall(void *data, size_t datalen, RIL_Token t) @@ -2053,6 +2120,9 @@ onRequest (int request, void *data, size_t datalen, RIL_Token t) case RIL_REQUEST_CDMA_SEND_SMS: requestCdmaSendSMS(data, datalen, t); break; + case RIL_REQUEST_IMS_SEND_SMS: + requestImsSendSMS(data, datalen, t); + break; case RIL_REQUEST_SETUP_DATA_CALL: requestSetupDataCall(data, datalen, t); break; @@ -2170,6 +2240,27 @@ onRequest (int request, void *data, size_t datalen, RIL_Token t) requestEnterSimPin(data, datalen, t); break; + case RIL_REQUEST_IMS_REGISTRATION_STATE: { + int reply[2]; + //0==unregistered, 1==registered + reply[0] = s_ims_registered; + + //to be used when changed to include service supporated info + //reply[1] = s_ims_services; + + // FORMAT_3GPP(1) vs FORMAT_3GPP2(2); + reply[1] = s_ims_format; + + RLOGD("IMS_REGISTRATION=%d, format=%d ", + reply[0], reply[1]); + if (reply[1] != -1) { + RIL_onRequestComplete(t, RIL_E_SUCCESS, reply, sizeof(reply)); + } else { + RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0); + } + break; + } + case RIL_REQUEST_VOICE_RADIO_TECH: { int tech = techFromModemType(TECH(sMdmInfo)); @@ -2929,6 +3020,18 @@ static void waitForClose() pthread_mutex_unlock(&s_state_mutex); } +static void sendUnsolImsNetworkStateChanged() +{ +#if 0 // to be used when unsol is changed to return data. + int reply[2]; + reply[0] = s_ims_registered; + reply[1] = s_ims_services; + reply[1] = s_ims_format; +#endif + RIL_onUnsolicitedResponse(RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED, + NULL, 0); +} + /** * Called by atchannel when an unsolicited line appears * This is called on atchannel's reader thread. AT commands may diff --git a/rild/Android.mk b/rild/Android.mk index f01b320..1f616b1 100644 --- a/rild/Android.mk +++ b/rild/Android.mk @@ -13,6 +13,10 @@ LOCAL_SHARED_LIBRARIES := \ libril \ libdl +# temporary hack for broken vendor rils +LOCAL_WHOLE_STATIC_LIBRARIES := \ + librilutils_static + LOCAL_CFLAGS := -DRIL_SHLIB LOCAL_MODULE:= rild