1/*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "hril_hdf.h"
17#ifdef UDEV_SUPPORT
18#include <libudev.h>
19#endif
20#include "dlfcn.h"
21#include "hdf_base.h"
22#include "hril_enum.h"
23#include "modem_adapter.h"
24#include "parameter.h"
25#include "stdlib.h"
26#include "telephony_log_c.h"
27#include "securec.h"
28
29#define RIL_VENDOR_LIB_PATH "const.sys.radio.vendorlib.path"
30#define VIRTUAL_MODEM_SWITCH  "const.booster.virtual_modem_switch"
31#define VIRTUAL_MODEM_DEFAULT_SWITCH  "false"
32#define TEL_SIM_SLOT_COUNT "const.telephony.slotCount"
33#define DEFAULT_SLOT_COUNT "1"
34#define BASE_HEX 16
35
36static void *g_dlHandle = NULL;
37static struct HRilReport g_reportOps = {
38    OnCallReport,
39    OnDataReport,
40    OnModemReport,
41    OnNetworkReport,
42    OnSimReport,
43    OnSmsReport,
44    OnTimerCallback
45};
46
47static int32_t GetVendorLibPath(char *path)
48{
49    int32_t code = -1;
50    code = GetParameter(RIL_VENDOR_LIB_PATH, "", path, PARAMETER_SIZE);
51    char simSlotCount[PARAMETER_SIZE] = {0};
52    GetParameter(TEL_SIM_SLOT_COUNT, DEFAULT_SLOT_COUNT, simSlotCount, PARAMETER_SIZE);
53    int32_t slotCount = atoi(simSlotCount);
54    char virtualModemSwitch[PARAMETER_SIZE] = {0};
55    GetParameter(VIRTUAL_MODEM_SWITCH, VIRTUAL_MODEM_DEFAULT_SWITCH, virtualModemSwitch, PARAMETER_SIZE);
56    if (slotCount == 0 && strcmp(virtualModemSwitch, "true") == 0) {
57        if (strcpy_s(path, PARAMETER_SIZE, "libril_msgtransfer.z.so") == EOK) {
58            TELEPHONY_LOGI("virtualModemSwitch on set path libril_msgtransfer.z.so");
59            code = 1;
60        }
61    }
62    if (code > 0) {
63        return HDF_SUCCESS;
64    }
65    TELEPHONY_LOGE("Failed to get vendor library path through system properties. err:%{public}d", code);
66    return HDF_FAILURE;
67}
68
69#ifdef UDEV_SUPPORT
70static UsbDeviceInfo *GetPresetInformation(const char *vId, const char *pId)
71{
72    if (vId == NULL || pId == NULL) {
73        return NULL;
74    }
75    char *out = NULL;
76    UsbDeviceInfo *uDevInfo = NULL;
77    int32_t idVendor = (int32_t)strtol(vId, &out, BASE_HEX);
78    int32_t idProduct = (int32_t)strtol(pId, &out, BASE_HEX);
79    for (uint32_t i = 0; i < sizeof(g_usbModemVendorInfo) / sizeof(UsbDeviceInfo); i++) {
80        if (g_usbModemVendorInfo[i].idVendor == idVendor && g_usbModemVendorInfo[i].idProduct == idProduct) {
81            TELEPHONY_LOGI("list index:%{public}d", i);
82            uDevInfo = &g_usbModemVendorInfo[i];
83            break;
84        }
85    }
86    return uDevInfo;
87}
88#endif
89
90static UsbDeviceInfo *GetUsbDeviceInfo(void)
91{
92    UsbDeviceInfo *uDevInfo = NULL;
93#ifdef UDEV_SUPPORT
94    struct udev *udev;
95    struct udev_enumerate *enumerate;
96    struct udev_list_entry *devices, *devListEntry;
97    struct udev_device *dev;
98
99    udev = udev_new();
100    if (udev == NULL) {
101        TELEPHONY_LOGE("Can't create udev");
102        return uDevInfo;
103    }
104    enumerate = udev_enumerate_new(udev);
105    if (enumerate == NULL) {
106        TELEPHONY_LOGE("Can't create enumerate");
107        udev_unref(udev);
108        return uDevInfo;
109    }
110    udev_enumerate_add_match_subsystem(enumerate, "tty");
111    udev_enumerate_scan_devices(enumerate);
112    devices = udev_enumerate_get_list_entry(enumerate);
113    udev_list_entry_foreach(devListEntry, devices) {
114        const char *path = udev_list_entry_get_name(devListEntry);
115        if (path == NULL) {
116            continue;
117        }
118        dev = udev_device_new_from_syspath(udev, path);
119        if (dev == NULL) {
120            continue;
121        }
122        dev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device");
123        if (!dev) {
124            TELEPHONY_LOGE("Unable to find parent usb device.");
125            return uDevInfo;
126        }
127        const char *cIdVendor = udev_device_get_sysattr_value(dev, "idVendor");
128        const char *cIdProduct = udev_device_get_sysattr_value(dev, "idProduct");
129        uDevInfo = GetPresetInformation(cIdVendor, cIdProduct);
130        udev_device_unref(dev);
131        if (uDevInfo != NULL) {
132            break;
133        }
134    }
135    udev_enumerate_unref(enumerate);
136    udev_unref(udev);
137#endif
138    return uDevInfo;
139}
140
141static void LoadVendor(void)
142{
143    const char *rilLibPath = NULL;
144    char vendorLibPath[PARAMETER_SIZE] = {0};
145    // Pointer to ril init function in vendor ril
146    const HRilOps *(*rilInitOps)(const struct HRilReport *) = NULL;
147    // functions returned by ril init function in vendor ril
148    const HRilOps *ops = NULL;
149
150    UsbDeviceInfo *uDevInfo = GetUsbDeviceInfo();
151    if (GetVendorLibPath(vendorLibPath) == HDF_SUCCESS) {
152        rilLibPath = vendorLibPath;
153    } else if (uDevInfo != NULL) {
154        rilLibPath = uDevInfo->libPath;
155    } else {
156        TELEPHONY_LOGE("no vendor lib");
157        return;
158    }
159    if (rilLibPath == NULL || rilLibPath[0] == '\0') {
160        TELEPHONY_LOGE("dynamic library path is empty");
161        return;
162    }
163
164    TELEPHONY_LOGI("RilInit LoadVendor start with rilLibPath:%{public}s", rilLibPath);
165    g_dlHandle = dlopen(rilLibPath, RTLD_NOW);
166    if (g_dlHandle == NULL) {
167        TELEPHONY_LOGE("dlopen %{public}s is fail. %{public}s", rilLibPath, dlerror());
168        return;
169    }
170    rilInitOps = (const HRilOps *(*)(const struct HRilReport *))dlsym(g_dlHandle, "RilInitOps");
171    if (rilInitOps == NULL) {
172        dlclose(g_dlHandle);
173        TELEPHONY_LOGE("RilInit not defined or exported");
174        return;
175    }
176    HRilInit();
177    ops = rilInitOps(&g_reportOps);
178    HRilRegOps(ops);
179    TELEPHONY_LOGI("HRilRegOps completed");
180}
181
182void InitRilAdapter(void)
183{
184    LoadVendor();
185}
186
187void ReleaseRilAdapter(void)
188{
189    if (g_dlHandle == NULL) {
190        TELEPHONY_LOGE("g_dlHandle has been null");
191        return;
192    }
193    dlclose(g_dlHandle);
194}
195