1/* //device/system/rild/rild.c
2**
3** Copyright 2006 The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <dlfcn.h>
21#include <string.h>
22#include <stdint.h>
23#include <unistd.h>
24#include <fcntl.h>
25#include <errno.h>
26
27#include <telephony/ril.h>
28#define LOG_TAG "RILD"
29#include <utils/Log.h>
30#include <cutils/properties.h>
31#include <cutils/sockets.h>
32#include <sys/capability.h>
33#include <sys/prctl.h>
34
35#include <private/android_filesystem_config.h>
36#include "hardware/qemu_pipe.h"
37
38#define LIB_PATH_PROPERTY   "rild.libpath"
39#define LIB_ARGS_PROPERTY   "rild.libargs"
40#define MAX_LIB_ARGS        16
41
42static void usage(const char *argv0)
43{
44    fprintf(stderr, "Usage: %s -l <ril impl library> [-- <args for impl library>]\n", argv0);
45    exit(EXIT_FAILURE);
46}
47
48extern char rild[MAX_SOCKET_NAME_LENGTH];
49
50extern void RIL_register (const RIL_RadioFunctions *callbacks);
51
52extern void RIL_onRequestComplete(RIL_Token t, RIL_Errno e,
53                           void *response, size_t responselen);
54
55
56#if defined(ANDROID_MULTI_SIM)
57extern void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
58                                size_t datalen, RIL_SOCKET_ID socket_id);
59#else
60extern void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
61                                size_t datalen);
62#endif
63
64extern void RIL_requestTimedCallback (RIL_TimedCallback callback,
65                               void *param, const struct timeval *relativeTime);
66
67
68static struct RIL_Env s_rilEnv = {
69    RIL_onRequestComplete,
70    RIL_onUnsolicitedResponse,
71    RIL_requestTimedCallback
72};
73
74extern void RIL_startEventLoop();
75
76static int make_argv(char * args, char ** argv)
77{
78    // Note: reserve argv[0]
79    int count = 1;
80    char * tok;
81    char * s = args;
82
83    while ((tok = strtok(s, " \0"))) {
84        argv[count] = tok;
85        s = NULL;
86        count++;
87    }
88    return count;
89}
90
91/*
92 * switchUser - Switches UID to radio, preserving CAP_NET_ADMIN capabilities.
93 * Our group, cache, was set by init.
94 */
95void switchUser() {
96    prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
97    setuid(AID_RADIO);
98
99    struct __user_cap_header_struct header;
100    memset(&header, 0, sizeof(header));
101    header.version = _LINUX_CAPABILITY_VERSION_3;
102    header.pid = 0;
103
104    struct __user_cap_data_struct data[2];
105    memset(&data, 0, sizeof(data));
106
107    data[CAP_TO_INDEX(CAP_NET_ADMIN)].effective |= CAP_TO_MASK(CAP_NET_ADMIN);
108    data[CAP_TO_INDEX(CAP_NET_ADMIN)].permitted |= CAP_TO_MASK(CAP_NET_ADMIN);
109
110    data[CAP_TO_INDEX(CAP_NET_RAW)].effective |= CAP_TO_MASK(CAP_NET_RAW);
111    data[CAP_TO_INDEX(CAP_NET_RAW)].permitted |= CAP_TO_MASK(CAP_NET_RAW);
112
113    if (capset(&header, &data[0]) == -1) {
114        RLOGE("capset failed: %s", strerror(errno));
115        exit(EXIT_FAILURE);
116    }
117}
118
119int main(int argc, char **argv)
120{
121    const char * rilLibPath = NULL;
122    char **rilArgv;
123    void *dlHandle;
124    const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **);
125    const RIL_RadioFunctions *funcs;
126    char libPath[PROPERTY_VALUE_MAX];
127    unsigned char hasLibArgs = 0;
128
129    int i;
130    const char *clientId = NULL;
131    RLOGD("**RIL Daemon Started**");
132    RLOGD("**RILd param count=%d**", argc);
133
134    umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
135    for (i = 1; i < argc ;) {
136        if (0 == strcmp(argv[i], "-l") && (argc - i > 1)) {
137            rilLibPath = argv[i + 1];
138            i += 2;
139        } else if (0 == strcmp(argv[i], "--")) {
140            i++;
141            hasLibArgs = 1;
142            break;
143        } else if (0 == strcmp(argv[i], "-c") &&  (argc - i > 1)) {
144            clientId = argv[i+1];
145            i += 2;
146        } else {
147            usage(argv[0]);
148        }
149    }
150
151    if (clientId == NULL) {
152        clientId = "0";
153    } else if (atoi(clientId) >= MAX_RILDS) {
154        RLOGE("Max Number of rild's supported is: %d", MAX_RILDS);
155        exit(0);
156    }
157    if (strncmp(clientId, "0", MAX_CLIENT_ID_LENGTH)) {
158        RIL_setRilSocketName(strncat(rild, clientId, MAX_SOCKET_NAME_LENGTH));
159    }
160
161    if (rilLibPath == NULL) {
162        if ( 0 == property_get(LIB_PATH_PROPERTY, libPath, NULL)) {
163            // No lib sepcified on the command line, and nothing set in props.
164            // Assume "no-ril" case.
165            goto done;
166        } else {
167            rilLibPath = libPath;
168        }
169    }
170
171    /* special override when in the emulator */
172#if 1
173    {
174        static char*  arg_overrides[5];
175        static char   arg_device[32];
176        int           done = 0;
177
178#define  REFERENCE_RIL_PATH  "libreference-ril.so"
179
180        /* first, read /proc/cmdline into memory */
181        char          buffer[1024], *p, *q;
182        int           len;
183        int           fd = open("/proc/cmdline",O_RDONLY);
184
185        if (fd < 0) {
186            RLOGD("could not open /proc/cmdline:%s", strerror(errno));
187            goto OpenLib;
188        }
189
190        do {
191            len = read(fd,buffer,sizeof(buffer)); }
192        while (len == -1 && errno == EINTR);
193
194        if (len < 0) {
195            RLOGD("could not read /proc/cmdline:%s", strerror(errno));
196            close(fd);
197            goto OpenLib;
198        }
199        close(fd);
200
201        if (strstr(buffer, "android.qemud=") != NULL)
202        {
203            /* the qemud daemon is launched after rild, so
204            * give it some time to create its GSM socket
205            */
206            int  tries = 5;
207#define  QEMUD_SOCKET_NAME    "qemud"
208
209            while (1) {
210                int  fd;
211
212                sleep(1);
213
214                fd = qemu_pipe_open("qemud:gsm");
215                if (fd < 0) {
216                    fd = socket_local_client(
217                                QEMUD_SOCKET_NAME,
218                                ANDROID_SOCKET_NAMESPACE_RESERVED,
219                                SOCK_STREAM );
220                }
221                if (fd >= 0) {
222                    close(fd);
223                    snprintf( arg_device, sizeof(arg_device), "%s/%s",
224                                ANDROID_SOCKET_DIR, QEMUD_SOCKET_NAME );
225
226                    arg_overrides[1] = "-s";
227                    arg_overrides[2] = arg_device;
228                    done = 1;
229                    break;
230                }
231                RLOGD("could not connect to %s socket: %s",
232                    QEMUD_SOCKET_NAME, strerror(errno));
233                if (--tries == 0)
234                    break;
235            }
236            if (!done) {
237                RLOGE("could not connect to %s socket (giving up): %s",
238                    QEMUD_SOCKET_NAME, strerror(errno));
239                while(1)
240                    sleep(0x00ffffff);
241            }
242        }
243
244        /* otherwise, try to see if we passed a device name from the kernel */
245        if (!done) do {
246#define  KERNEL_OPTION  "android.ril="
247#define  DEV_PREFIX     "/dev/"
248
249            p = strstr( buffer, KERNEL_OPTION );
250            if (p == NULL)
251                break;
252
253            p += sizeof(KERNEL_OPTION)-1;
254            q  = strpbrk( p, " \t\n\r" );
255            if (q != NULL)
256                *q = 0;
257
258            snprintf( arg_device, sizeof(arg_device), DEV_PREFIX "%s", p );
259            arg_device[sizeof(arg_device)-1] = 0;
260            arg_overrides[1] = "-d";
261            arg_overrides[2] = arg_device;
262            done = 1;
263
264        } while (0);
265
266        if (done) {
267            argv = arg_overrides;
268            argc = 3;
269            i    = 1;
270            hasLibArgs = 1;
271            rilLibPath = REFERENCE_RIL_PATH;
272
273            RLOGD("overriding with %s %s", arg_overrides[1], arg_overrides[2]);
274        }
275    }
276OpenLib:
277#endif
278    switchUser();
279
280    dlHandle = dlopen(rilLibPath, RTLD_NOW);
281
282    if (dlHandle == NULL) {
283        RLOGE("dlopen failed: %s", dlerror());
284        exit(EXIT_FAILURE);
285    }
286
287    RIL_startEventLoop();
288
289    rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
290
291    if (rilInit == NULL) {
292        RLOGE("RIL_Init not defined or exported in %s\n", rilLibPath);
293        exit(EXIT_FAILURE);
294    }
295
296    if (hasLibArgs) {
297        rilArgv = argv + i - 1;
298        argc = argc -i + 1;
299    } else {
300        static char * newArgv[MAX_LIB_ARGS];
301        static char args[PROPERTY_VALUE_MAX];
302        rilArgv = newArgv;
303        property_get(LIB_ARGS_PROPERTY, args, "");
304        argc = make_argv(args, rilArgv);
305    }
306
307    rilArgv[argc++] = "-c";
308    rilArgv[argc++] = clientId;
309    RLOGD("RIL_Init argc = %d clientId = %s", argc, rilArgv[argc-1]);
310
311    // Make sure there's a reasonable argv[0]
312    rilArgv[0] = argv[0];
313
314    funcs = rilInit(&s_rilEnv, argc, rilArgv);
315    RLOGD("RIL_Init rilInit completed");
316
317    RIL_register(funcs);
318
319    RLOGD("RIL_Init RIL_register completed");
320
321done:
322
323    RLOGD("RIL_Init starting sleep loop");
324    while (true) {
325        sleep(UINT32_MAX);
326    }
327}
328