/* * Copyright (C) 2023 Huawei Device Co., Ltd. * 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 "gsm_user_data_pdu.h" #include "gsm_pdu_hex_value.h" #include "gsm_sms_common_utils.h" #include "gsm_user_data_decode.h" #include "gsm_user_data_encode.h" #include "securec.h" #include "telephony_log_wrapper.h" namespace OHOS { namespace Telephony { using namespace std; static constexpr uint8_t NORMAL_BYTE_BITS = 8; static constexpr uint8_t SLIDE_DATA_STEP = 2; bool GsmUserDataPdu::EncodeUserDataPdu( SmsWriteBuffer &buffer, const struct SmsUDPackage *(&userData), DataCodingScheme scheme) { if (userData == nullptr) { TELEPHONY_LOGE("nullptr error."); return false; } auto encodePdu = std::make_shared(shared_from_this()); if (encodePdu == nullptr) { TELEPHONY_LOGE("nullptr error."); return false; } bool result = false; switch (scheme) { case DATA_CODING_7BIT: result = encodePdu->EncodeGsmPdu(buffer, userData); break; case DATA_CODING_8BIT: result = encodePdu->Encode8bitPdu(buffer, userData); break; case DATA_CODING_UCS2: result = encodePdu->EncodeUcs2Pdu(buffer, userData); break; default: break; } TELEPHONY_LOGI("userData encode result:%{public}d", result); return result; } bool GsmUserDataPdu::DecodeUserDataPdu( SmsReadBuffer &buffer, bool bHeaderInd, DataCodingScheme scheme, struct SmsUDPackage *userData) { if (userData == nullptr) { TELEPHONY_LOGE("nullptr error."); return false; } if (memset_s(userData, sizeof(struct SmsUDPackage), 0x00, sizeof(struct SmsUDPackage)) != EOK) { TELEPHONY_LOGE("memset_s error."); return false; } auto decodePdu = std::make_shared(shared_from_this()); if (decodePdu == nullptr) { TELEPHONY_LOGE("nullptr error."); return false; } bool result = false; switch (scheme) { case DATA_CODING_7BIT: result = decodePdu->DecodeGsmPdu(buffer, bHeaderInd, userData, nullptr); break; case DATA_CODING_8BIT: result = decodePdu->Decode8bitPdu(buffer, bHeaderInd, userData, nullptr); break; case DATA_CODING_UCS2: result = decodePdu->DecodeUcs2Pdu(buffer, bHeaderInd, userData, nullptr); break; default: break; } TELEPHONY_LOGI("userData decode result:%{public}d", result); return result; } bool GsmUserDataPdu::DecodeUserDataPdu(SmsReadBuffer &buffer, bool bHeaderInd, DataCodingScheme scheme, struct SmsUDPackage *userData, struct SmsTpud *pTPUD) { if (userData == nullptr || pTPUD == nullptr) { TELEPHONY_LOGE("nullptr error."); return false; } if (memset_s(userData, sizeof(struct SmsUDPackage), 0x00, sizeof(struct SmsUDPackage)) != EOK) { TELEPHONY_LOGE("memset_s error."); return false; } auto decodePdu = std::make_shared(shared_from_this()); if (decodePdu == nullptr) { TELEPHONY_LOGE("nullptr error."); return false; } bool result = false; switch (scheme) { case DATA_CODING_7BIT: result = decodePdu->DecodeGsmPdu(buffer, bHeaderInd, userData, pTPUD); break; case DATA_CODING_8BIT: result = decodePdu->Decode8bitPdu(buffer, bHeaderInd, userData, pTPUD); break; case DATA_CODING_UCS2: result = decodePdu->DecodeUcs2Pdu(buffer, bHeaderInd, userData, pTPUD); break; case DATA_CODING_EUCKR: result = decodePdu->DecodeUcs2Pdu(buffer, bHeaderInd, userData, pTPUD); break; default: break; } TELEPHONY_LOGI("userData decode result:%{public}d", result); return result; } void GsmUserDataPdu::ResetUserData(struct SmsUDPackage &userData) { userData.length = 0; if (memset_s(userData.data, sizeof(userData.data), 0x00, sizeof(userData.data)) != EOK) { TELEPHONY_LOGE("memset_s error!"); return; } } bool GsmUserDataPdu::GetHeaderCnt(SmsReadBuffer &buffer, struct SmsUDPackage *userData, uint8_t &udhl, uint16_t i) { if (i >= MAX_UD_HEADER_NUM) { TELEPHONY_LOGE("index invalid."); return false; } uint16_t headerLen = 0; uint16_t current = buffer.GetIndex(); if (!DecodeHeader(buffer, userData->header[i], headerLen)) { TELEPHONY_LOGE("memset_s fail."); return false; } if (headerLen == 0) { userData->length = 0; if (memset_s(userData->data, sizeof(userData->data), 0x00, sizeof(userData->data)) != EOK) { TELEPHONY_LOGE("memset_s fail."); } return false; } if ((buffer.GetIndex() - current) > (udhl + SLIDE_DATA_STEP)) { userData->length = 0; if (memset_s(userData->data, sizeof(userData->data), 0x00, sizeof(userData->data)) != EOK) { TELEPHONY_LOGE("memset_s fail."); } return false; } userData->headerCnt++; return true; } void GsmUserDataPdu::EncodeHeader(SmsWriteBuffer &buffer, const struct SmsUDH header) { switch (header.udhType) { case UDH_CONCAT_8BIT: case UDH_CONCAT_16BIT: EncodeHeaderConcat(buffer, header); break; case UDH_APP_PORT_8BIT: EncodeHeaderAppPort8bit(buffer, header); break; case UDH_APP_PORT_16BIT: EncodeHeaderAppPort16bit(buffer, header); break; case UDH_ALTERNATE_REPLY_ADDRESS: EncodeHeaderReplyAddress(buffer, header); break; case UDH_SINGLE_SHIFT: if (!buffer.WriteByte(UDH_SINGLE_SHIFT)) { TELEPHONY_LOGE("write data error."); return; } if (!buffer.WriteByte(HEX_VALUE_01)) { TELEPHONY_LOGE("write data error."); return; } if (!buffer.WriteByte(header.udh.singleShift.langId)) { TELEPHONY_LOGE("write data error."); return; } break; case UDH_LOCKING_SHIFT: if (!buffer.WriteByte(UDH_LOCKING_SHIFT)) { TELEPHONY_LOGE("write data error."); return; } if (!buffer.WriteByte(HEX_VALUE_01)) { TELEPHONY_LOGE("write data error."); return; } if (!buffer.WriteByte(header.udh.lockingShift.langId)) { TELEPHONY_LOGE("write data error."); return; } break; default: break; } } void GsmUserDataPdu::EncodeHeaderAppPort8bit(SmsWriteBuffer &buffer, const struct SmsUDH header) { if (!buffer.WriteByte(UDH_APP_PORT_8BIT)) { TELEPHONY_LOGE("write data error."); return; } if (!buffer.WriteByte(HEX_VALUE_02)) { TELEPHONY_LOGE("write data error."); return; } if (!buffer.WriteByte(header.udh.appPort8bit.destPort)) { TELEPHONY_LOGE("write data error."); return; } if (!buffer.WriteByte(header.udh.appPort8bit.originPort)) { TELEPHONY_LOGE("write data error."); return; } } void GsmUserDataPdu::EncodeHeaderAppPort16bit(SmsWriteBuffer &buffer, const struct SmsUDH header) { if (!buffer.WriteByte(UDH_APP_PORT_16BIT)) { TELEPHONY_LOGE("write data error."); return; } if (!buffer.WriteByte(HEX_VALUE_04)) { TELEPHONY_LOGE("write data error."); return; } if (!buffer.WriteByte(static_cast(header.udh.appPort16bit.destPort >> NORMAL_BYTE_BITS))) { TELEPHONY_LOGE("write data error."); return; } if (!buffer.WriteByte(static_cast(header.udh.appPort16bit.destPort & HEX_VALUE_00FF))) { TELEPHONY_LOGE("write data error."); return; } if (!buffer.WriteByte(static_cast(header.udh.appPort16bit.originPort >> NORMAL_BYTE_BITS))) { TELEPHONY_LOGE("write data error."); return; } if (!buffer.WriteByte(static_cast(header.udh.appPort16bit.originPort & HEX_VALUE_00FF))) { TELEPHONY_LOGE("write data error."); return; } } void GsmUserDataPdu::EncodeHeaderReplyAddress(SmsWriteBuffer &buffer, const struct SmsUDH header) { if (!buffer.WriteByte(UDH_ALTERNATE_REPLY_ADDRESS)) { TELEPHONY_LOGE("write data error."); return; } std::string encodedAddr; GsmSmsParamCodec codec; if (!codec.EncodeAddressPdu(&(header.udh.alternateAddress), encodedAddr)) { TELEPHONY_LOGE("EncodeHeader EncodeAddressPdu fail"); return; } uint8_t addrLen = encodedAddr.size(); if (!buffer.WriteByte(addrLen)) { TELEPHONY_LOGE("write data error."); return; } if (buffer.data_ == nullptr || (buffer.GetIndex() + addrLen) > buffer.GetSize()) { TELEPHONY_LOGE("buffer data error."); return; } if (memcpy_s(buffer.data_.get() + buffer.GetIndex(), addrLen, encodedAddr.data(), addrLen) != EOK) { TELEPHONY_LOGE("EncodeHeader memcpy_s error"); return; } } void GsmUserDataPdu::EncodeHeaderConcat(SmsWriteBuffer &buffer, const struct SmsUDH header) { switch (header.udhType) { case UDH_CONCAT_8BIT: EncodeHeaderConcat8Bit(buffer, header); break; case UDH_CONCAT_16BIT: EncodeHeaderConcat16Bit(buffer, header); break; case UDH_NONE: default: break; } } void GsmUserDataPdu::EncodeHeaderConcat8Bit(SmsWriteBuffer &buffer, const struct SmsUDH &header) { if (!buffer.WriteByte(UDH_CONCAT_8BIT)) { TELEPHONY_LOGE("write data error."); return; } if (!buffer.WriteByte(HEX_VALUE_03)) { TELEPHONY_LOGE("write data error."); return; } if (!buffer.WriteByte(header.udh.concat8bit.msgRef)) { TELEPHONY_LOGE("write data error."); return; } if (!buffer.WriteByte(header.udh.concat8bit.totalSeg)) { TELEPHONY_LOGE("write data error."); return; } if (!buffer.WriteByte(header.udh.concat8bit.seqNum)) { TELEPHONY_LOGE("write data error."); return; } } void GsmUserDataPdu::EncodeHeaderConcat16Bit(SmsWriteBuffer &buffer, const struct SmsUDH &header) { if (!buffer.WriteByte(UDH_CONCAT_16BIT)) { TELEPHONY_LOGE("write data error."); return; } if (!buffer.WriteByte(HEX_VALUE_04)) { TELEPHONY_LOGE("write data error."); return; } if (!buffer.WriteByte(static_cast(header.udh.concat16bit.msgRef >> NORMAL_BYTE_BITS))) { TELEPHONY_LOGE("write data error."); return; } if (!buffer.WriteByte(header.udh.concat16bit.msgRef & HEX_VALUE_00FF)) { TELEPHONY_LOGE("write data error."); return; } if (!buffer.WriteByte(header.udh.concat16bit.totalSeg)) { TELEPHONY_LOGE("write data error."); return; } if (!buffer.WriteByte(header.udh.concat16bit.seqNum)) { TELEPHONY_LOGE("write data error."); return; } } bool GsmUserDataPdu::DecodeHeader(SmsReadBuffer &buffer, struct SmsUDH &pHeader, uint16_t &headerLen) { headerLen = buffer.GetIndex(); uint8_t oneByte = 0; if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } pHeader.udhType = oneByte; switch (pHeader.udhType) { case UDH_CONCAT_8BIT: if (!DecodeHeaderConcat8Bit(buffer, pHeader)) { TELEPHONY_LOGE("decode fail."); return false; } break; case UDH_CONCAT_16BIT: if (!DecodeHeaderConcat16Bit(buffer, pHeader)) { TELEPHONY_LOGE("decode fail."); return false; } break; case UDH_APP_PORT_8BIT: if (!DecodeHeaderAppPort8Bit(buffer, pHeader)) { TELEPHONY_LOGE("decode fail."); return false; } break; case UDH_APP_PORT_16BIT: if (!DecodeHeaderAppPort16Bit(buffer, pHeader)) { TELEPHONY_LOGE("decode fail."); return false; } break; default: { if (!DecodeHeaderPartData(buffer, pHeader, oneByte)) { TELEPHONY_LOGE("decode fail."); return false; } } } if (buffer.GetIndex() > headerLen) { headerLen = buffer.GetIndex() - headerLen; } else { headerLen = 0; } return true; } bool GsmUserDataPdu::DecodeHeaderPartData(SmsReadBuffer &buffer, struct SmsUDH &pHeader, uint8_t oneByte) { pHeader.udhType = oneByte; switch (pHeader.udhType) { case UDH_SPECIAL_SMS: if (!DecodeHeaderSpecialSms(buffer, pHeader)) { TELEPHONY_LOGE("decode fail."); return false; } break; case UDH_ALTERNATE_REPLY_ADDRESS: if (!DecodeHeaderReplyAddress(buffer, pHeader)) { TELEPHONY_LOGE("decode fail."); return false; } break; case UDH_SINGLE_SHIFT: if (!DecodeHeaderSingleShift(buffer, pHeader)) { TELEPHONY_LOGE("decode fail."); return false; } break; case UDH_LOCKING_SHIFT: if (!DecodeHeaderLockingShift(buffer, pHeader)) { TELEPHONY_LOGE("decode fail."); return false; } break; default: { if (!DecodeHeaderDefaultCase(buffer, pHeader)) { TELEPHONY_LOGE("decode fail."); return false; } break; } } return true; } bool GsmUserDataPdu::DecodeHeaderConcat8Bit(SmsReadBuffer &buffer, struct SmsUDH &pHeader) { uint8_t oneByte = 0; if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } if (oneByte == 0) { return false; } if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } pHeader.udh.concat8bit.msgRef = oneByte; if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } pHeader.udh.concat8bit.totalSeg = oneByte; if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } pHeader.udh.concat8bit.seqNum = oneByte; DebugDecodeHeader(pHeader); return true; } bool GsmUserDataPdu::DecodeHeaderConcat16Bit(SmsReadBuffer &buffer, struct SmsUDH &pHeader) { uint8_t oneByte = 0; if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } if (oneByte == 0) { return false; } if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } pHeader.udh.concat16bit.msgRef = oneByte; if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } oneByte |= pHeader.udh.concat16bit.msgRef << NORMAL_BYTE_BITS; pHeader.udh.concat16bit.msgRef = static_cast(oneByte); if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } pHeader.udh.concat16bit.totalSeg = oneByte; if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } pHeader.udh.concat16bit.seqNum = oneByte; DebugDecodeHeader(pHeader); return true; } bool GsmUserDataPdu::DecodeHeaderAppPort8Bit(SmsReadBuffer &buffer, struct SmsUDH &pHeader) { uint8_t oneByte = 0; if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } if (oneByte == 0) { TELEPHONY_LOGE("oneByte 0."); return false; } if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } pHeader.udh.appPort8bit.destPort = oneByte; if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } pHeader.udh.appPort8bit.originPort = oneByte; DebugDecodeHeader(pHeader); return true; } bool GsmUserDataPdu::DecodeHeaderAppPort16Bit(SmsReadBuffer &buffer, struct SmsUDH &pHeader) { uint8_t oneByte = 0; if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } if (oneByte == 0) { TELEPHONY_LOGE("pickByte 0."); return false; } if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } pHeader.udh.appPort16bit.destPort = oneByte; if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } uint16_t port = oneByte; port |= pHeader.udh.appPort16bit.destPort << NORMAL_BYTE_BITS; pHeader.udh.appPort16bit.destPort = static_cast(port); if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } pHeader.udh.appPort16bit.originPort = oneByte; if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } port = oneByte; port |= pHeader.udh.appPort16bit.originPort << NORMAL_BYTE_BITS; pHeader.udh.appPort16bit.originPort = static_cast(port); DebugDecodeHeader(pHeader); return true; } bool GsmUserDataPdu::DecodeHeaderSpecialSms(SmsReadBuffer &buffer, struct SmsUDH &pHeader) { uint8_t oneByte = 0; if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } if (oneByte != HEX_VALUE_02) { return false; } TELEPHONY_LOGI("Decoding special sms udh."); uint8_t pickByte = 0; if (!buffer.PickOneByte(pickByte)) { TELEPHONY_LOGE("get data error."); return false; } pHeader.udh.specialInd.bStore = static_cast(pickByte & HEX_VALUE_80); if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } pHeader.udh.specialInd.msgInd = static_cast(oneByte & HEX_VALUE_7F); if (!buffer.PickOneByte(pickByte)) { TELEPHONY_LOGE("get data error."); return false; } pHeader.udh.specialInd.waitMsgNum = pickByte; return true; } bool GsmUserDataPdu::DecodeHeaderReplyAddress(SmsReadBuffer &buffer, struct SmsUDH &pHeader) { uint8_t oneByte = 0; if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } if (oneByte == 0) { return false; } GsmSmsParamCodec codec; if (!codec.DecodeAddressPdu(buffer, &(pHeader.udh.alternateAddress))) { return false; } TELEPHONY_LOGI("alternate reply address [%{private}s]", pHeader.udh.alternateAddress.address); return true; } bool GsmUserDataPdu::DecodeHeaderSingleShift(SmsReadBuffer &buffer, struct SmsUDH &pHeader) { uint8_t oneByte = 0; if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } if (oneByte == 0) { return false; } if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } pHeader.udh.singleShift.langId = oneByte; TELEPHONY_LOGI("singleShift.langId [%{public}02x]", pHeader.udh.singleShift.langId); return true; } bool GsmUserDataPdu::DecodeHeaderLockingShift(SmsReadBuffer &buffer, struct SmsUDH &pHeader) { uint8_t oneByte = 0; if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } if (oneByte == 0) { return false; } if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } pHeader.udh.lockingShift.langId = oneByte; TELEPHONY_LOGI("lockingShift.langId [%{public}02x]", pHeader.udh.lockingShift.langId); return true; } bool GsmUserDataPdu::DecodeHeaderDefaultCase(SmsReadBuffer &buffer, struct SmsUDH &pHeader) { uint8_t oneByte = 0; TELEPHONY_LOGI("Not Supported Header Type [%{public}02x]", pHeader.udhType); if (!buffer.ReadByte(oneByte)) { TELEPHONY_LOGE("get data error."); return false; } TELEPHONY_LOGI("IEDL [%{public}u]", oneByte); buffer.MoveForward(oneByte); return true; } void GsmUserDataPdu::DebugDecodeHeader(const struct SmsUDH &pHeader) { switch (pHeader.udhType) { case UDH_CONCAT_8BIT: { TELEPHONY_LOGI("concat8bit.seqNum [%{public}02x]", pHeader.udh.concat8bit.seqNum); break; } case UDH_CONCAT_16BIT: { TELEPHONY_LOGI("concat16bit.seqNum [%{public}02x]", pHeader.udh.concat16bit.seqNum); break; } case UDH_APP_PORT_8BIT: { TELEPHONY_LOGI("appPort8bit.destPort [%{public}02x]", pHeader.udh.appPort8bit.destPort); TELEPHONY_LOGI("appPort8bit.originPort [%{public}02x]", pHeader.udh.appPort8bit.originPort); break; } case UDH_APP_PORT_16BIT: { TELEPHONY_LOGI("appPort16bit.destPort [%{public}04x]", pHeader.udh.appPort16bit.destPort); TELEPHONY_LOGI("appPort16bit.originPort [%{public}04x]", pHeader.udh.appPort16bit.originPort); break; } case UDH_SPECIAL_SMS: { TELEPHONY_LOGI("Decoding special sms udh."); break; } case UDH_ALTERNATE_REPLY_ADDRESS: break; case UDH_SINGLE_SHIFT: { TELEPHONY_LOGI("singleShift.langId [%{public}02x]", pHeader.udh.singleShift.langId); break; } case UDH_LOCKING_SHIFT: { TELEPHONY_LOGI("lockingShift.langId [%{public}02x]", pHeader.udh.lockingShift.langId); break; } default: break; } } } // namespace Telephony } // namespace OHOS