Merge lp:~phablet-team/ofono/update-july-first into lp:~phablet-team/ofono/ubuntu
- update-july-first
- Merge into ubuntu
Status: | Merged |
---|---|
Approved by: | Tony Espy |
Approved revision: | 6903 |
Merged at revision: | 6898 |
Proposed branch: | lp:~phablet-team/ofono/update-july-first |
Merge into: | lp:~phablet-team/ofono/ubuntu |
Diff against target: |
2564 lines (+1823/-149) 27 files modified
Makefile.am (+16/-2) configure.ac (+11/-0) debian/changelog (+20/-0) debian/control (+2/-1) drivers/mtkmodem/mtkutil.h (+1/-0) drivers/qcommsimmodem/qcom_msim_constants.h (+2/-0) drivers/qcommsimmodem/qcom_msim_modem.c (+56/-0) drivers/qcommsimmodem/qcom_msim_modem.h (+25/-0) drivers/qcommsimmodem/radio-settings.c (+270/-0) drivers/rilmodem/gprs-context.c (+86/-6) drivers/rilmodem/radio-settings.c (+1/-1) drivers/rilmodem/radio-settings.h (+3/-0) drivers/rilmodem/rilutil.h (+1/-0) gril/gril.c (+4/-15) include/dns-client.h (+120/-0) include/radio-settings.h (+3/-0) plugins/c-ares-dns-client.c (+767/-0) plugins/mtk.c (+12/-2) plugins/ril.c (+20/-6) src/dns-client.c (+128/-0) src/gprs.c (+260/-102) src/radio-settings.c (+3/-3) test/list-contexts (+1/-1) test/list-modems (+5/-4) test/rilmodem/sim/simtestutil.py (+4/-4) test/rilmodem/sim/test-no-sims-offline (+1/-1) test/rilmodem/sim/test-sims-offline (+1/-1) |
To merge this branch: | bzr merge lp:~phablet-team/ofono/update-july-first |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tony Espy | Approve | ||
Review via email: mp+263462@code.launchpad.net |
Commit message
[Tony Espy]
* test/rilmodem/sim: fix testing scripts for arale
* test: reverse meaning of list-modems -p
[ Alfonso Sanchez-Beato ]
* gril: cleanup traces
* src/gprs.c: set preferred for the used IA APN
* rilmodem, mtkmodem, plugins/ril.c, plugins/mtk.c: retry when a
context deactivation request has finished with an error
* build, include, plugins/
src/gprs.c: resolve MMS proxy/MMSC host name (LP: #1417976)
[ Ratchanan Srirattanamet ]
* build, rilmodem, qcommsimmodem, plugins/ril.c,
src/radio-
Description of the change
[Tony Espy]
* test/rilmodem/sim: fix testing scripts for arale
* test: reverse meaning of list-modems -p
[ Alfonso Sanchez-Beato ]
* gril: cleanup traces
* src/gprs.c: set preferred for the used IA APN
* rilmodem, mtkmodem, plugins/ril.c, plugins/mtk.c: retry when a
context deactivation request has finished with an error
* build, include, plugins/
src/gprs.c: resolve MMS proxy/MMSC host name (LP: #1417976)
[ Ratchanan Srirattanamet ]
* build, rilmodem, qcommsimmodem, plugins/ril.c,
src/radio-
- 6899. By Alfonso Sanchez-Beato
-
Add c-ares-dev to debian build dependencies
- 6900. By Alfonso Sanchez-Beato
-
Fix printing context properties
- 6901. By Alfonso Sanchez-Beato
-
Fix changelog
- 6902. By Alfonso Sanchez-Beato
-
Fix debian package version
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote : | # |
Changelog changed adding bug numbers, but I have not reverted the package version number because the actual version produced in the silo is 6900. I think that at some moment there has been a mismatch between changelog version and the version in the package name, and using 6900 we get both things synced again.
Tony Espy (awe) wrote : | # |
The version in the silo is 6900 because that's what you told it to build.
Again, the latest version in trunk is 6897, so the merge will be 6898 in trunk, which != 6900, so the versions will actually not be in sync... Let's discuss at our net/telephony meeting.
Tony Espy (awe) : | # |
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote : | # |
No, I did change the version to 6898 in the changelog, and the package version was still 6900. It takes the bzr branch version, not the version from the changelog.
- 6903. By Alfonso Sanchez-Beato
-
Fix changelog
Tony Espy (awe) : | # |
- 6904. By Alfonso Sanchez-Beato
-
Fix package version
- 6905. By Alfonso Sanchez-Beato
-
Fix version to 6900
Tony Espy (awe) wrote : | # |
Tested mako ( rc/ubuntu #1 ); Note, the latest version of network-manager (4ubuntu15.1.4) from the overlay PPA was also installed.
Ran the Basic Tests from:
https:/
Also verified that MMS can be sent & received using AT&T, which provision an APN that specifies a non-dotted-
Verified that the list-modems privacy flag has indeed been reversed, and also checked that the rilmodem test scripts didn't break due to an arale fix contained in this merge. Did find one bug in one of the test scripts though ( not a regression ):
https:/
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote : | # |
Tested on arale (devel-proposed, #41)
Ran the Basic Tests from:
https:/
Restoring cellular mode after unsetting flight mode failed, which was expected as the NM version that fixes this has not landed in wily.
Verified bugs #1438715, #1457775, #1361864 are fixed.
MMS tx/rx working for pepephone operator.
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote : | # |
Tested on krillin (rc-proposed, #56)
Ran the Basic Tests from:
https:/
Verified bugs #1438715, #1361864 are fixed.
MMS tx/rx working for pepephone operator.
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote : | # |
Vivid silo tested on krillin (rc-proposed, #56)
Ran the Basic Tests from:
https:/
MMS tx/rx working for pepephone operator.
Preview Diff
1 | === modified file 'Makefile.am' |
2 | --- Makefile.am 2015-05-20 16:32:09 +0000 |
3 | +++ Makefile.am 2015-07-02 17:01:42 +0000 |
4 | @@ -19,7 +19,8 @@ |
5 | include/cdma-connman.h include/gnss.h \ |
6 | include/private-network.h include/cdma-netreg.h \ |
7 | include/cdma-provision.h include/handsfree.h \ |
8 | - include/sim-mnclength.h include/spn-table.h |
9 | + include/sim-mnclength.h include/spn-table.h \ |
10 | + include/dns-client.h |
11 | |
12 | nodist_pkginclude_HEADERS = include/version.h |
13 | |
14 | @@ -172,6 +173,10 @@ |
15 | drivers/rilmodem/radio-settings.c \ |
16 | drivers/rilmodem/call-barring.c \ |
17 | drivers/rilmodem/phonebook.c |
18 | + |
19 | +builtin_modules += qcommsimmodem |
20 | +builtin_sources += drivers/qcommsimmodem/qcom_msim_modem.c \ |
21 | + drivers/qcommsimmodem/radio-settings.c |
22 | endif |
23 | |
24 | if ISIMODEM |
25 | @@ -530,6 +535,14 @@ |
26 | builtin_sources += plugins/mnclength.c |
27 | endif |
28 | |
29 | +if CARES |
30 | +builtin_modules += c_ares_dns_client |
31 | +builtin_sources += plugins/c-ares-dns-client.c |
32 | + |
33 | +builtin_cflags += @CARES_CFLAGS@ |
34 | +builtin_libadd += @CARES_LIBS@ |
35 | +endif |
36 | + |
37 | if MAINTAINER_MODE |
38 | builtin_modules += example_history |
39 | builtin_sources += examples/history.c |
40 | @@ -585,7 +598,8 @@ |
41 | src/cdma-smsutil.h src/cdma-smsutil.c \ |
42 | src/cdma-sms.c src/private-network.c src/cdma-netreg.c \ |
43 | src/cdma-provision.c src/handsfree.c \ |
44 | - src/sim-mnclength.c src/spn-table.c |
45 | + src/sim-mnclength.c src/spn-table.c \ |
46 | + src/dns-client.c |
47 | |
48 | src_ofonod_LDADD = $(builtin_libadd) @GLIB_LIBS@ @DBUS_LIBS@ -ldl |
49 | |
50 | |
51 | === modified file 'configure.ac' |
52 | --- configure.ac 2014-06-24 18:59:26 +0000 |
53 | +++ configure.ac 2015-07-02 17:01:42 +0000 |
54 | @@ -188,6 +188,17 @@ |
55 | AC_SUBST(BLUEZ_LIBS) |
56 | AM_CONDITIONAL(BLUETOOTH, test "${enable_bluetooth}" != "no") |
57 | |
58 | +AC_ARG_ENABLE(cares, AC_HELP_STRING([--disable-cares], |
59 | + [disable DNS client using c-ares library]), |
60 | + [enable_cares=${enableval}]) |
61 | +if (test "${enable_cares}" != "no"); then |
62 | + PKG_CHECK_MODULES(CARES, libcares, dummy=yes, |
63 | + AC_MSG_ERROR(libcares is required)) |
64 | +fi |
65 | +AC_SUBST(CARES_CFLAGS) |
66 | +AC_SUBST(CARES_LIBS) |
67 | +AM_CONDITIONAL(CARES, test "${enable_cares}" != "no") |
68 | + |
69 | AC_ARG_ENABLE(nettime, AC_HELP_STRING([--disable-nettime], |
70 | [disable Nettime plugin]), |
71 | [enable_nettime=${enableval}]) |
72 | |
73 | === modified file 'debian/changelog' |
74 | --- debian/changelog 2015-05-21 08:44:39 +0000 |
75 | +++ debian/changelog 2015-07-02 17:01:42 +0000 |
76 | @@ -1,3 +1,23 @@ |
77 | +ofono (1.12.bzr6900+15.04.20150701-0ubuntu1) UNRELEASED; urgency=medium |
78 | + |
79 | + [Tony Espy] |
80 | + * test/rilmodem/sim: fix testing scripts for arale (LP: #1457775) |
81 | + * test: reverse meaning of list-modems -p (LP: #1438715) |
82 | + |
83 | + [ Alfonso Sanchez-Beato ] |
84 | + * gril: cleanup traces |
85 | + * src/gprs.c: set preferred for the used IA APN (LP: #1361864) |
86 | + * rilmodem, mtkmodem, plugins/ril.c, plugins/mtk.c: retry when a |
87 | + context deactivation request has finished with an error |
88 | + * build, include, plugins/c-ares-dns-client.c, src/dns-client.c, |
89 | + src/gprs.c: resolve MMS proxy/MMSC host name (LP: #1417976) |
90 | + |
91 | + [ Ratchanan Srirattanamet ] |
92 | + * build, rilmodem, qcommsimmodem, plugins/ril.c, |
93 | + src/radio-settings.c: add multi-sim support for qcommsimmodem |
94 | + |
95 | + -- Alfonso Sanchez-Beato (email Canonical) <alfonso.sanchez-beato@canonical.com> Wed, 01 Jul 2015 08:40:36 +0200 |
96 | + |
97 | ofono (1.12.bzr6896+15.04.20150521-0ubuntu1) vivid; urgency=medium |
98 | |
99 | [ Ratchanan Srirattanamet ] |
100 | |
101 | === modified file 'debian/control' |
102 | --- debian/control 2015-01-12 10:01:50 +0000 |
103 | +++ debian/control 2015-07-02 17:01:42 +0000 |
104 | @@ -13,7 +13,8 @@ |
105 | libudev-dev, |
106 | udev, |
107 | libbluetooth-dev (>= 4.30), |
108 | - mobile-broadband-provider-info |
109 | + mobile-broadband-provider-info, |
110 | + libc-ares-dev |
111 | Standards-Version: 3.9.4 |
112 | Homepage: http://www.ofono.org/ |
113 | # If you aren't a member of ~phablet-team but need to upload |
114 | |
115 | === modified file 'drivers/mtkmodem/mtkutil.h' |
116 | --- drivers/mtkmodem/mtkutil.h 2015-01-29 14:50:30 +0000 |
117 | +++ drivers/mtkmodem/mtkutil.h 2015-07-02 17:01:42 +0000 |
118 | @@ -35,6 +35,7 @@ |
119 | void mtk_detach_received(struct ofono_modem *modem); |
120 | |
121 | void mtk_reset_all_modems(void); |
122 | +void mtk_reset_modem(struct ofono_modem *modem); |
123 | |
124 | const char *mtk_request_id_to_string(int req); |
125 | const char *mtk_unsol_request_to_string(int req); |
126 | |
127 | === modified file 'drivers/qcommsimmodem/qcom_msim_constants.h' |
128 | --- drivers/qcommsimmodem/qcom_msim_constants.h 2015-04-23 13:08:30 +0000 |
129 | +++ drivers/qcommsimmodem/qcom_msim_constants.h 2015-07-02 17:01:42 +0000 |
130 | @@ -22,6 +22,8 @@ |
131 | #ifndef QCOM_MSIM_CONSTANTS_H |
132 | #define QCOM_MSIM_CONSTANTS_H |
133 | |
134 | +#define QCOMMSIM_NUM_SLOTS_MAX 2 |
135 | + |
136 | #define QCOM_MSIM_RIL_REQUEST_SET_UICC_SUBSCRIPTION 115 |
137 | |
138 | #endif /* QCOM_MSIM_CONSTANTS_H */ |
139 | |
140 | === added file 'drivers/qcommsimmodem/qcom_msim_modem.c' |
141 | --- drivers/qcommsimmodem/qcom_msim_modem.c 1970-01-01 00:00:00 +0000 |
142 | +++ drivers/qcommsimmodem/qcom_msim_modem.c 2015-07-02 17:01:42 +0000 |
143 | @@ -0,0 +1,56 @@ |
144 | +/* |
145 | + * |
146 | + * oFono - Open Source Telephony - RIL Modem Support |
147 | + * |
148 | + * Copyright (C) 2008-2011 Intel Corporation. All rights reserved. |
149 | + * Copyright (C) 2012 Canonical, Ltd. All rights reserved. |
150 | + * Copyright (C) 2015 Ratchanan Srirattanamet. |
151 | + * |
152 | + * This program is free software; you can redistribute it and/or modify |
153 | + * it under the terms of the GNU General Public License version 2 as |
154 | + * published by the Free Software Foundation. |
155 | + * |
156 | + * This program is distributed in the hope that it will be useful, |
157 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
158 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
159 | + * GNU General Public License for more details. |
160 | + * |
161 | + * You should have received a copy of the GNU General Public License |
162 | + * along with this program; if not, write to the Free Software |
163 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
164 | + * |
165 | + */ |
166 | + |
167 | +#ifdef HAVE_CONFIG_H |
168 | +#include <config.h> |
169 | +#endif |
170 | + |
171 | +#include <glib.h> |
172 | +#include <gril.h> |
173 | + |
174 | +#define OFONO_API_SUBJECT_TO_CHANGE |
175 | +#include <ofono/plugin.h> |
176 | +#include <ofono/log.h> |
177 | +#include <ofono/types.h> |
178 | + |
179 | +#include "qcom_msim_modem.h" |
180 | + |
181 | +static int qcom_msim_modem_init(void) |
182 | +{ |
183 | + DBG(""); |
184 | + |
185 | + qcom_msim_radio_settings_init(); |
186 | + |
187 | + return 0; |
188 | +} |
189 | + |
190 | +static void qcom_msim_modem_exit(void) |
191 | +{ |
192 | + DBG(""); |
193 | + |
194 | + qcom_msim_radio_settings_exit(); |
195 | +} |
196 | + |
197 | +OFONO_PLUGIN_DEFINE(qcommsimmodem, "Qualcomm multi-sim modem driver", VERSION, |
198 | + OFONO_PLUGIN_PRIORITY_DEFAULT, |
199 | + qcom_msim_modem_init, qcom_msim_modem_exit) |
200 | |
201 | === added file 'drivers/qcommsimmodem/qcom_msim_modem.h' |
202 | --- drivers/qcommsimmodem/qcom_msim_modem.h 1970-01-01 00:00:00 +0000 |
203 | +++ drivers/qcommsimmodem/qcom_msim_modem.h 2015-07-02 17:01:42 +0000 |
204 | @@ -0,0 +1,25 @@ |
205 | +/* |
206 | + * |
207 | + * oFono - Open Source Telephony - RIL Modem Support |
208 | + * |
209 | + * Copyright (C) 2015 Ratchanan Srirattanamet |
210 | + * |
211 | + * This program is free software; you can redistribute it and/or modify |
212 | + * it under the terms of the GNU General Public License version 2 as |
213 | + * published by the Free Software Foundation. |
214 | + * |
215 | + * This program is distributed in the hope that it will be useful, |
216 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
217 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
218 | + * GNU General Public License for more details. |
219 | + * |
220 | + * You should have received a copy of the GNU General Public License |
221 | + * along with this program; if not, write to the Free Software |
222 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
223 | + * |
224 | + */ |
225 | + |
226 | +#define QCOMMSIMMODEM "qcommsimmodem" |
227 | + |
228 | +extern void qcom_msim_radio_settings_init(void); |
229 | +extern void qcom_msim_radio_settings_exit(void); |
230 | |
231 | === added file 'drivers/qcommsimmodem/radio-settings.c' |
232 | --- drivers/qcommsimmodem/radio-settings.c 1970-01-01 00:00:00 +0000 |
233 | +++ drivers/qcommsimmodem/radio-settings.c 2015-07-02 17:01:42 +0000 |
234 | @@ -0,0 +1,270 @@ |
235 | +/* |
236 | + * |
237 | + * oFono - Open Source Telephony |
238 | + * |
239 | + * Copyright (C) 2014 Canonical Ltd. |
240 | + * Copyright (C) 2015 Ratchanan Srirattanamet |
241 | + * |
242 | + * This program is free software; you can redistribute it and/or modify |
243 | + * it under the terms of the GNU General Public License version 2 as |
244 | + * published by the Free Software Foundation. |
245 | + * |
246 | + * This program is distributed in the hope that it will be useful, |
247 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
248 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
249 | + * GNU General Public License for more details. |
250 | + * |
251 | + * You should have received a copy of the GNU General Public License |
252 | + * along with this program; if not, write to the Free Software |
253 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
254 | + * |
255 | + */ |
256 | + |
257 | +#ifdef HAVE_CONFIG_H |
258 | +#include <config.h> |
259 | +#endif |
260 | + |
261 | +#define _GNU_SOURCE |
262 | +#include <stdio.h> |
263 | +#include <stdlib.h> |
264 | +#include <string.h> |
265 | +#include <errno.h> |
266 | + |
267 | +#include <glib.h> |
268 | + |
269 | +#include <ofono/log.h> |
270 | +#include <ofono/modem.h> |
271 | +#include <ofono/radio-settings.h> |
272 | + |
273 | +#include "gril.h" |
274 | +#include "grilrequest.h" |
275 | +#include "grilreply.h" |
276 | + |
277 | +#include "drivers/rilmodem/radio-settings.h" |
278 | +#include "drivers/rilmodem/rilutil.h" |
279 | +#include "qcom_msim_modem.h" |
280 | +#include "qcom_msim_constants.h" |
281 | + |
282 | +struct qcom_msim_pending_pref_setting { |
283 | + struct ofono_radio_settings *rs; |
284 | + int pref; |
285 | + int pending_gsm_pref_remaining; |
286 | + struct cb_data *cbd; |
287 | +}; |
288 | + |
289 | +struct qcom_msim_set_2g_rat { |
290 | + struct ofono_radio_settings *rs; |
291 | + struct qcom_msim_pending_pref_setting *pps; |
292 | +}; |
293 | + |
294 | +static struct ofono_radio_settings *multisim_rs[QCOMMSIM_NUM_SLOTS_MAX]; |
295 | +static int multisim_num_slots; |
296 | + |
297 | +static void qcom_msim_set_rat_cb(struct ril_msg *message, gpointer user_data) |
298 | +{ |
299 | + struct cb_data *cbd = user_data; |
300 | + struct ofono_radio_settings *rs = cbd->user; |
301 | + struct radio_data *rd = ofono_radio_settings_get_data(rs); |
302 | + ofono_radio_settings_rat_mode_set_cb_t cb = cbd->cb; |
303 | + |
304 | + if (message->error == RIL_E_SUCCESS) { |
305 | + g_ril_print_response_no_args(rd->ril, message); |
306 | + CALLBACK_WITH_SUCCESS(cb, cbd->data); |
307 | + } else { |
308 | + ofono_error("%s: rat mode setting failed", __func__); |
309 | + CALLBACK_WITH_FAILURE(cb, cbd->data); |
310 | + } |
311 | +} |
312 | + |
313 | +static void qcom_msim_set_2g_rat_cb(struct ril_msg *message, |
314 | + gpointer user_data) |
315 | +{ |
316 | + struct qcom_msim_set_2g_rat *set_2g_rat_data = user_data; |
317 | + struct ofono_radio_settings *rs = set_2g_rat_data->rs; |
318 | + struct qcom_msim_pending_pref_setting *pps = set_2g_rat_data->pps; |
319 | + struct radio_data *rd = ofono_radio_settings_get_data(rs); |
320 | + ofono_radio_settings_rat_mode_set_cb_t cb; |
321 | + struct parcel rilp; |
322 | + |
323 | + pps->pending_gsm_pref_remaining -= 1; |
324 | + |
325 | + if (message->error == RIL_E_SUCCESS) { |
326 | + g_ril_print_response_no_args(rd->ril, message); |
327 | + ofono_radio_settings_set_rat_mode(rs, |
328 | + OFONO_RADIO_ACCESS_MODE_GSM); |
329 | + } else { |
330 | + ofono_error("%s: rat mode setting failed", __func__); |
331 | + if (pps->cbd != NULL) { |
332 | + cb = pps->cbd->cb; |
333 | + CALLBACK_WITH_FAILURE(cb, pps->cbd->data); |
334 | + |
335 | + g_free(pps->cbd); |
336 | + pps->cbd = NULL; |
337 | + } |
338 | + } |
339 | + |
340 | + if (pps->pending_gsm_pref_remaining == 0) { |
341 | + if (pps->cbd != NULL) { |
342 | + struct radio_data *pps_rd = |
343 | + ofono_radio_settings_get_data(pps->rs); |
344 | + g_ril_request_set_preferred_network_type(pps_rd->ril, |
345 | + pps->pref, &rilp); |
346 | + |
347 | + if (g_ril_send(pps_rd->ril, |
348 | + RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, |
349 | + &rilp, qcom_msim_set_rat_cb, pps->cbd, |
350 | + g_free) == 0) { |
351 | + ofono_error("%s: unable to set rat mode", |
352 | + __func__); |
353 | + cb = pps->cbd->cb; |
354 | + CALLBACK_WITH_FAILURE(cb, pps->cbd->data); |
355 | + g_free(pps->cbd); |
356 | + } |
357 | + } |
358 | + |
359 | + g_free(pps); |
360 | + } |
361 | +} |
362 | + |
363 | +static void qcom_msim_set_rat_mode(struct ofono_radio_settings *rs, |
364 | + enum ofono_radio_access_mode mode, |
365 | + ofono_radio_settings_rat_mode_set_cb_t cb, |
366 | + void *data) |
367 | +{ |
368 | + struct radio_data *rd = ofono_radio_settings_get_data(rs); |
369 | + struct cb_data *cbd = cb_data_new(cb, data, rs); |
370 | + struct parcel rilp; |
371 | + int pref = PREF_NET_TYPE_GSM_WCDMA; |
372 | + |
373 | + switch (mode) { |
374 | + case OFONO_RADIO_ACCESS_MODE_ANY: |
375 | + pref = PREF_NET_TYPE_LTE_GSM_WCDMA; |
376 | + break; |
377 | + case OFONO_RADIO_ACCESS_MODE_GSM: |
378 | + pref = PREF_NET_TYPE_GSM_ONLY; |
379 | + break; |
380 | + case OFONO_RADIO_ACCESS_MODE_UMTS: |
381 | + pref = PREF_NET_TYPE_GSM_WCDMA; |
382 | + break; |
383 | + case OFONO_RADIO_ACCESS_MODE_LTE: |
384 | + pref = PREF_NET_TYPE_LTE_GSM_WCDMA; |
385 | + break; |
386 | + } |
387 | + |
388 | + if (pref != PREF_NET_TYPE_GSM_ONLY && multisim_num_slots > 1) { |
389 | + struct qcom_msim_pending_pref_setting *pps = |
390 | + g_try_new0(struct qcom_msim_pending_pref_setting, 1); |
391 | + int i; |
392 | + |
393 | + pps->rs = rs; |
394 | + pps->pref = pref; |
395 | + pps->cbd = cbd; |
396 | + pps->pending_gsm_pref_remaining = 0; |
397 | + |
398 | + for (i = 0; i < QCOMMSIM_NUM_SLOTS_MAX; i++) { |
399 | + struct radio_data *temp_rd; |
400 | + struct qcom_msim_set_2g_rat *set_2g_rat_data; |
401 | + |
402 | + if (multisim_rs[i] == rs || multisim_rs[i] == NULL) |
403 | + continue; |
404 | + |
405 | + temp_rd = ofono_radio_settings_get_data(multisim_rs[i]); |
406 | + set_2g_rat_data = |
407 | + g_try_new0(struct qcom_msim_set_2g_rat, 1); |
408 | + set_2g_rat_data->pps = pps; |
409 | + set_2g_rat_data->rs = multisim_rs[i]; |
410 | + |
411 | + g_ril_request_set_preferred_network_type(temp_rd->ril, |
412 | + PREF_NET_TYPE_GSM_ONLY, &rilp); |
413 | + |
414 | + if (g_ril_send(temp_rd->ril, |
415 | + RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, |
416 | + &rilp, qcom_msim_set_2g_rat_cb, |
417 | + set_2g_rat_data, g_free) == 0) { |
418 | + ofono_error("%s: unable to set rat mode", |
419 | + __func__); |
420 | + pps->cbd = NULL; |
421 | + g_free(cbd); |
422 | + g_free(set_2g_rat_data); |
423 | + CALLBACK_WITH_FAILURE(cb, data); |
424 | + break; |
425 | + } else { |
426 | + pps->pending_gsm_pref_remaining += 1; |
427 | + } |
428 | + } |
429 | + |
430 | + if (pps->pending_gsm_pref_remaining == 0) |
431 | + g_free(pps); |
432 | + } else { |
433 | + g_ril_request_set_preferred_network_type(rd->ril, pref, &rilp); |
434 | + |
435 | + if (g_ril_send(rd->ril, RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, |
436 | + &rilp, qcom_msim_set_rat_cb, cbd, |
437 | + g_free) == 0) { |
438 | + ofono_error("%s: unable to set rat mode", __func__); |
439 | + g_free(cbd); |
440 | + CALLBACK_WITH_FAILURE(cb, data); |
441 | + } |
442 | + } |
443 | +} |
444 | + |
445 | +static int qcom_msim_radio_settings_probe(struct ofono_radio_settings *rs, |
446 | + unsigned int vendor, void *user) |
447 | +{ |
448 | + struct ril_radio_settings_driver_data *rs_init_data = user; |
449 | + struct radio_data *rsd = g_try_new0(struct radio_data, 1); |
450 | + int slot_id; |
451 | + |
452 | + if (rsd == NULL) { |
453 | + ofono_error("%s: cannot allocate memory", __func__); |
454 | + return -ENOMEM; |
455 | + } |
456 | + |
457 | + rsd->ril = g_ril_clone(rs_init_data->gril); |
458 | + rsd->modem = rs_init_data->modem; |
459 | + |
460 | + ofono_radio_settings_set_data(rs, rsd); |
461 | + |
462 | + ril_set_fast_dormancy(rs, FALSE, ril_delayed_register, rs); |
463 | + |
464 | + slot_id = ofono_modem_get_integer(rsd->modem, "Slot"); |
465 | + multisim_rs[slot_id] = rs; |
466 | + multisim_num_slots += 1; |
467 | + |
468 | + return 0; |
469 | +} |
470 | + |
471 | +static void qcom_msim_radio_settings_remove(struct ofono_radio_settings *rs) |
472 | +{ |
473 | + struct radio_data *rd = ofono_radio_settings_get_data(rs); |
474 | + int slot_id = ofono_modem_get_integer(rd->modem, "Slot"); |
475 | + |
476 | + multisim_rs[slot_id] = NULL; |
477 | + multisim_num_slots -= 1; |
478 | + |
479 | + ofono_radio_settings_set_data(rs, NULL); |
480 | + |
481 | + g_ril_unref(rd->ril); |
482 | + g_free(rd); |
483 | +} |
484 | + |
485 | +static struct ofono_radio_settings_driver driver = { |
486 | + .name = QCOMMSIMMODEM, |
487 | + .probe = qcom_msim_radio_settings_probe, |
488 | + .remove = qcom_msim_radio_settings_remove, |
489 | + .query_rat_mode = ril_query_rat_mode, |
490 | + .set_rat_mode = qcom_msim_set_rat_mode, |
491 | + .query_fast_dormancy = ril_query_fast_dormancy, |
492 | + .set_fast_dormancy = ril_set_fast_dormancy, |
493 | + .query_modem_rats = ril_query_modem_rats |
494 | +}; |
495 | + |
496 | +void qcom_msim_radio_settings_init(void) |
497 | +{ |
498 | + ofono_radio_settings_driver_register(&driver); |
499 | +} |
500 | + |
501 | +void qcom_msim_radio_settings_exit(void) |
502 | +{ |
503 | + ofono_radio_settings_driver_unregister(&driver); |
504 | +} |
505 | |
506 | === modified file 'drivers/rilmodem/gprs-context.c' |
507 | --- drivers/rilmodem/gprs-context.c 2015-05-20 16:32:09 +0000 |
508 | +++ drivers/rilmodem/gprs-context.c 2015-07-02 17:01:42 +0000 |
509 | @@ -46,6 +46,10 @@ |
510 | |
511 | #include "gprs.h" |
512 | #include "rilmodem.h" |
513 | +#include "drivers/mtkmodem/mtkutil.h" |
514 | + |
515 | +#define NUM_DEACTIVATION_RETRIES 4 |
516 | +#define TIME_BETWEEN_DEACT_RETRIES_S 2 |
517 | |
518 | enum state { |
519 | STATE_IDLE, |
520 | @@ -56,18 +60,23 @@ |
521 | |
522 | struct gprs_context_data { |
523 | GRil *ril; |
524 | + struct ofono_modem *modem; |
525 | + unsigned vendor; |
526 | gint active_ctx_cid; |
527 | gint active_rild_cid; |
528 | enum state state; |
529 | guint call_list_id; |
530 | char *apn; |
531 | enum ofono_gprs_context_type type; |
532 | + int deact_retries; |
533 | }; |
534 | |
535 | static void ril_gprs_context_deactivate_primary(struct ofono_gprs_context *gc, |
536 | unsigned int id, |
537 | ofono_gprs_context_cb_t cb, |
538 | void *data); |
539 | +static void ril_deactivate_data_call_cb(struct ril_msg *message, |
540 | + gpointer user_data); |
541 | |
542 | static void set_context_disconnected(struct gprs_context_data *gcd) |
543 | { |
544 | @@ -318,6 +327,52 @@ |
545 | } |
546 | } |
547 | |
548 | +static gboolean reset_modem(gpointer data) |
549 | +{ |
550 | + mtk_reset_modem(data); |
551 | + |
552 | + return FALSE; |
553 | +} |
554 | + |
555 | +static gboolean retry_deactivate(gpointer user_data) |
556 | +{ |
557 | + struct cb_data *cbd = user_data; |
558 | + ofono_gprs_context_cb_t cb = cbd->cb; |
559 | + struct ofono_gprs_context *gc = cbd->user; |
560 | + struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc); |
561 | + struct req_deactivate_data_call request; |
562 | + struct parcel rilp; |
563 | + struct ofono_error error; |
564 | + |
565 | + /* We might have received a call list update while waiting */ |
566 | + if (gcd->state == STATE_IDLE) { |
567 | + if (cb) |
568 | + CALLBACK_WITH_SUCCESS(cb, cbd->data); |
569 | + |
570 | + g_free(cbd); |
571 | + |
572 | + return FALSE; |
573 | + } |
574 | + |
575 | + request.cid = gcd->active_rild_cid; |
576 | + request.reason = RIL_DEACTIVATE_DATA_CALL_NO_REASON; |
577 | + |
578 | + g_ril_request_deactivate_data_call(gcd->ril, &request, &rilp, &error); |
579 | + |
580 | + if (g_ril_send(gcd->ril, RIL_REQUEST_DEACTIVATE_DATA_CALL, &rilp, |
581 | + ril_deactivate_data_call_cb, cbd, g_free) == 0) { |
582 | + |
583 | + ofono_error("%s: send DEACTIVATE_DATA_CALL failed for apn: %s", |
584 | + __func__, gcd->apn); |
585 | + if (cb) |
586 | + CALLBACK_WITH_FAILURE(cb, cbd->data); |
587 | + |
588 | + g_free(cbd); |
589 | + } |
590 | + |
591 | + return FALSE; |
592 | +} |
593 | + |
594 | static void ril_deactivate_data_call_cb(struct ril_msg *message, |
595 | gpointer user_data) |
596 | { |
597 | @@ -329,7 +384,6 @@ |
598 | |
599 | DBG("*gc: %p", gc); |
600 | |
601 | - /* Reply has no data... */ |
602 | if (message->error == RIL_E_SUCCESS) { |
603 | |
604 | g_ril_print_response_no_args(gcd->ril, message); |
605 | @@ -337,9 +391,9 @@ |
606 | active_ctx_cid = gcd->active_ctx_cid; |
607 | set_context_disconnected(gcd); |
608 | |
609 | - /* If the deactivate was a result of a shutdown, |
610 | - * there won't be call back, so _deactivated() |
611 | - * needs to be called directly. |
612 | + /* |
613 | + * If the deactivate was a result of a shutdown, there won't be |
614 | + * call back, so _deactivated() needs to be called directly. |
615 | */ |
616 | if (cb) |
617 | CALLBACK_WITH_SUCCESS(cb, cbd->data); |
618 | @@ -351,8 +405,31 @@ |
619 | __func__, gcd->apn, |
620 | ril_error_to_string(message->error)); |
621 | |
622 | - if (cb) |
623 | - CALLBACK_WITH_FAILURE(cb, cbd->data); |
624 | + /* |
625 | + * It has been detected that some modems fail the deactivation |
626 | + * temporarily. We do retries to handle that case. |
627 | + */ |
628 | + if (--(gcd->deact_retries) > 0) { |
629 | + struct cb_data *cbd2; |
630 | + |
631 | + cbd2 = cb_data_new(cb, cbd->data, gc); |
632 | + g_timeout_add_seconds(TIME_BETWEEN_DEACT_RETRIES_S, |
633 | + retry_deactivate, cbd2); |
634 | + } else { |
635 | + ofono_error("%s: retry limit hit", __func__); |
636 | + |
637 | + if (cb) |
638 | + CALLBACK_WITH_FAILURE(cb, cbd->data); |
639 | + |
640 | + /* |
641 | + * Reset modem if MTK. TODO Failures deactivating a |
642 | + * context have not been reported for other modems, but |
643 | + * it would be good to have a generic method to force an |
644 | + * internal reset nonetheless. |
645 | + */ |
646 | + if (gcd->vendor == OFONO_RIL_VENDOR_MTK) |
647 | + g_idle_add(reset_modem, gcd->modem); |
648 | + } |
649 | } |
650 | } |
651 | |
652 | @@ -402,6 +479,7 @@ |
653 | goto error; |
654 | } |
655 | |
656 | + gcd->deact_retries = NUM_DEACTIVATION_RETRIES; |
657 | ret = g_ril_send(gcd->ril, RIL_REQUEST_DEACTIVATE_DATA_CALL, &rilp, |
658 | ril_deactivate_data_call_cb, cbd, g_free); |
659 | |
660 | @@ -438,6 +516,8 @@ |
661 | return -ENOMEM; |
662 | |
663 | gcd->ril = g_ril_clone(ril_data->gril); |
664 | + gcd->modem = ril_data->modem; |
665 | + gcd->vendor = vendor; |
666 | set_context_disconnected(gcd); |
667 | gcd->call_list_id = -1; |
668 | gcd->type = ril_data->type; |
669 | |
670 | === modified file 'drivers/rilmodem/radio-settings.c' |
671 | --- drivers/rilmodem/radio-settings.c 2015-01-29 14:50:30 +0000 |
672 | +++ drivers/rilmodem/radio-settings.c 2015-07-02 17:01:42 +0000 |
673 | @@ -229,7 +229,7 @@ |
674 | return FALSE; |
675 | } |
676 | |
677 | -static void ril_query_modem_rats(struct ofono_radio_settings *rs, |
678 | +void ril_query_modem_rats(struct ofono_radio_settings *rs, |
679 | ofono_radio_settings_modem_rats_query_cb_t cb, |
680 | void *data) |
681 | { |
682 | |
683 | === modified file 'drivers/rilmodem/radio-settings.h' |
684 | --- drivers/rilmodem/radio-settings.h 2015-01-29 14:50:30 +0000 |
685 | +++ drivers/rilmodem/radio-settings.h 2015-07-02 17:01:42 +0000 |
686 | @@ -42,3 +42,6 @@ |
687 | ofono_bool_t enable, |
688 | ofono_radio_settings_fast_dormancy_set_cb_t cb, |
689 | void *data); |
690 | +void ril_query_modem_rats(struct ofono_radio_settings *rs, |
691 | + ofono_radio_settings_modem_rats_query_cb_t cb, |
692 | + void *data); |
693 | |
694 | === modified file 'drivers/rilmodem/rilutil.h' |
695 | --- drivers/rilmodem/rilutil.h 2015-01-29 14:50:30 +0000 |
696 | +++ drivers/rilmodem/rilutil.h 2015-07-02 17:01:42 +0000 |
697 | @@ -75,6 +75,7 @@ |
698 | |
699 | struct ril_gprs_context_data { |
700 | GRil *gril; |
701 | + struct ofono_modem *modem; |
702 | enum ofono_gprs_context_type type; |
703 | }; |
704 | |
705 | |
706 | === modified file 'gril/gril.c' |
707 | --- gril/gril.c 2014-09-22 16:06:53 +0000 |
708 | +++ gril/gril.c 2015-07-02 17:01:42 +0000 |
709 | @@ -272,9 +272,6 @@ |
710 | return NULL; |
711 | } |
712 | |
713 | - DBG("req: %s, id: %d, data_len: %u", |
714 | - request_id_to_string(ril, req), id, data_len); |
715 | - |
716 | /* Full request size: header size plus buffer length */ |
717 | r->data_len = data_len + sizeof(header); |
718 | |
719 | @@ -375,9 +372,6 @@ |
720 | for (i = 0; i < count; i++) { |
721 | req = g_queue_peek_nth(p->command_queue, i); |
722 | |
723 | - DBG("comparing req->id: %d to message->serial_no: %d", |
724 | - req->id, message->serial_no); |
725 | - |
726 | if (req->id == message->serial_no) { |
727 | found = TRUE; |
728 | message->req = req->req; |
729 | @@ -393,7 +387,7 @@ |
730 | req->callback(message, req->user_data); |
731 | |
732 | len = g_queue_get_length(p->out_queue); |
733 | - DBG("requests in out_queue before removing: %d", len); |
734 | + |
735 | for (i = 0; i < len; i++) { |
736 | id = GPOINTER_TO_INT(g_queue_peek_nth( |
737 | p->out_queue, i)); |
738 | @@ -413,7 +407,7 @@ |
739 | } |
740 | |
741 | if (found == FALSE) |
742 | - DBG("Reply: %s serial_no: %d without a matching request!", |
743 | + ofono_error("No matching request for reply: %s serial_no: %d!", |
744 | request_id_to_string(p, message->req), |
745 | message->serial_no); |
746 | |
747 | @@ -584,11 +578,8 @@ |
748 | */ |
749 | |
750 | message_len = *len - 4; |
751 | - if (message_len < plen) { |
752 | - DBG("Not enough bytes for fixed record; len: %d avail: %d", |
753 | - plen, message_len); |
754 | + if (message_len < plen) |
755 | return NULL; |
756 | - } |
757 | |
758 | /* FIXME: add check for message_len = 0? */ |
759 | |
760 | @@ -738,7 +729,7 @@ |
761 | len = req->data_len; |
762 | |
763 | towrite = len - ril->req_bytes_written; |
764 | - DBG("req:%d,len:%zu,towrite:%zu", req->id, len, towrite); |
765 | + |
766 | #ifdef WRITE_SCHEDULER_DEBUG |
767 | if (towrite > 5) |
768 | towrite = 5; |
769 | @@ -1168,8 +1159,6 @@ |
770 | |
771 | g_queue_push_tail(p->command_queue, r); |
772 | |
773 | - DBG("calling wakeup_writer: command_queue len: %d", |
774 | - g_queue_get_length(p->command_queue)); |
775 | ril_wakeup_writer(p); |
776 | |
777 | if (rilp == NULL) |
778 | |
779 | === added file 'include/dns-client.h' |
780 | --- include/dns-client.h 1970-01-01 00:00:00 +0000 |
781 | +++ include/dns-client.h 2015-07-02 17:01:42 +0000 |
782 | @@ -0,0 +1,120 @@ |
783 | +/* |
784 | + * |
785 | + * DNS Client - provides an asynchronous DNS resolution client. |
786 | + * |
787 | + * This file originally created by Google, Inc. |
788 | + * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
789 | + * Copyright (c) 2015 Canonical Ltd. |
790 | + * |
791 | + * This program is free software; you can redistribute it and/or modify |
792 | + * it under the terms of the GNU General Public License version 2 as |
793 | + * published by the Free Software Foundation. |
794 | + * |
795 | + * This program is distributed in the hope that it will be useful, |
796 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
797 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
798 | + * GNU General Public License for more details. |
799 | + * |
800 | + * You should have received a copy of the GNU General Public License |
801 | + * along with this program; if not, write to the Free Software |
802 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
803 | + * |
804 | + */ |
805 | + |
806 | +#ifndef OFONO_DNS_CLIENT_H |
807 | +#define OFONO_DNS_CLIENT_H |
808 | + |
809 | +struct sockaddr; |
810 | + |
811 | +/** |
812 | + * SECTION:dns_client |
813 | + * @title: DNS client interface |
814 | + * @short_description: Functions for interacting with asynchronous DNS client |
815 | + */ |
816 | + |
817 | +/* |
818 | + * Enumeration of possible DNS request completion status codes. |
819 | + * These are intentionally consistent with shill error codes. |
820 | + */ |
821 | +typedef enum { |
822 | + OFONO_DNS_CLIENT_SUCCESS = 0, |
823 | + OFONO_DNS_CLIENT_ERROR_NO_DATA, |
824 | + OFONO_DNS_CLIENT_ERROR_FORM_ERR, |
825 | + OFONO_DNS_CLIENT_ERROR_SERVER_FAIL, |
826 | + OFONO_DNS_CLIENT_ERROR_NOT_FOUND, |
827 | + OFONO_DNS_CLIENT_ERROR_NOT_IMP, |
828 | + OFONO_DNS_CLIENT_ERROR_REFUSED, |
829 | + OFONO_DNS_CLIENT_ERROR_BAD_QUERY, |
830 | + OFONO_DNS_CLIENT_ERROR_NET_REFUSED, |
831 | + OFONO_DNS_CLIENT_ERROR_TIMED_OUT, |
832 | + OFONO_DNS_CLIENT_ERROR_UNKNOWN, |
833 | +} ofono_dns_client_status_t; |
834 | + |
835 | +/* |
836 | + * Callbacks of this type are provided by a client when initiating a DNS request |
837 | + * and invoked by the dns_client module when a request has completed. |
838 | + * |data| is user data supplied by the client. |
839 | + * |status| is the completion status of the request. |
840 | + * |ip_addr| is a struct sockaddr containing an IPv4 or IPv6 address if the |
841 | + * request succeeded and NULL otherwise. The callee should copy |ip_addr| if it |
842 | + * wishes to retain it beyond the lifetime of this callback. |
843 | + */ |
844 | +typedef void (*ofono_dns_client_callback_t)(void *data, |
845 | + ofono_dns_client_status_t status, |
846 | + struct sockaddr *ip_addr); |
847 | + |
848 | +/* |
849 | + * Opaque handle uniquely indentifying an in-progress request. |
850 | + */ |
851 | +typedef void *ofono_dns_client_request_t; |
852 | + |
853 | +struct ofono_dns_client_driver { |
854 | + const char *name; |
855 | + ofono_dns_client_request_t (*submit_request)(const char *hostname, |
856 | + const char *device, |
857 | + const char **servers, |
858 | + int timeout_ms, |
859 | + ofono_dns_client_callback_t cb, |
860 | + void *data); |
861 | + gboolean (*cancel_request)(ofono_dns_client_request_t request); |
862 | +}; |
863 | + |
864 | + |
865 | +/* |
866 | + * Initiate an asynchronous name resolution request for |hostname|. |
867 | + * |device| specifies the interface out which the request should be sent, or |
868 | + * NULL to use the default interface. |
869 | + * |servers| string array with name servers to query or NULL to use system |
870 | + * defaults |
871 | + * |timeout_ms| specifies a max timeout in milliseconds, or 0 to use the default |
872 | + * timeout (which depends on the plugin). |
873 | + * Returns an opaque handle identifying the request on success and NULL on |
874 | + * failure. Success indicates only that the request was initiated, not that the |
875 | + * request itself was successful. |
876 | + * When the request is complete, the callback |cb| will be invoked with |data| |
877 | + * passed as an arg. |
878 | + */ |
879 | +ofono_dns_client_request_t __ofono_dns_client_submit_request( |
880 | + const char *hostname, |
881 | + const char *device, |
882 | + const char **servers, |
883 | + int timeout_ms, |
884 | + ofono_dns_client_callback_t cb, |
885 | + void *data); |
886 | + |
887 | +/* |
888 | + * Cancel the request identified by |request|. Does not invoke the callback for |
889 | + * the cancelled request. |
890 | + */ |
891 | +void __ofono_dns_client_cancel_request(ofono_dns_client_request_t request); |
892 | + |
893 | +/* |
894 | + * Returns a human-friendly error string corresponding to |status|. |
895 | + */ |
896 | +const char *__ofono_dns_client_strerror(ofono_dns_client_status_t status); |
897 | + |
898 | +int ofono_dns_client_driver_register(struct ofono_dns_client_driver *driver); |
899 | +void ofono_dns_client_driver_unregister( |
900 | + const struct ofono_dns_client_driver *driver); |
901 | + |
902 | +#endif /* OFONO_DNS_CLIENT_H */ |
903 | |
904 | === modified file 'include/radio-settings.h' |
905 | --- include/radio-settings.h 2014-07-24 08:31:17 +0000 |
906 | +++ include/radio-settings.h 2015-07-02 17:01:42 +0000 |
907 | @@ -136,6 +136,9 @@ |
908 | void ofono_radio_settings_set_data(struct ofono_radio_settings *rs, void *data); |
909 | void *ofono_radio_settings_get_data(struct ofono_radio_settings *rs); |
910 | |
911 | +void ofono_radio_settings_set_rat_mode(struct ofono_radio_settings *rs, |
912 | + enum ofono_radio_access_mode mode); |
913 | + |
914 | #ifdef __cplusplus |
915 | } |
916 | #endif |
917 | |
918 | === added file 'plugins/c-ares-dns-client.c' |
919 | --- plugins/c-ares-dns-client.c 1970-01-01 00:00:00 +0000 |
920 | +++ plugins/c-ares-dns-client.c 2015-07-02 17:01:42 +0000 |
921 | @@ -0,0 +1,767 @@ |
922 | +/* |
923 | + * |
924 | + * DNS Client - provides an asynchronous DNS resolution client. |
925 | + * |
926 | + * The client is implemented using the c-ares library, and integrates with |
927 | + * glib's main event loop. It was originally written to be used by flimflam, |
928 | + * and it has been modified to integrate with ofono. See http://c-ares.haxx.se |
929 | + * and http://developer.gnome.org/glib for c-ares and glib documentation. |
930 | + * |
931 | + * This file originally created by Google, Inc. |
932 | + * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
933 | + * Copyright (c) 2015 Canonical Ltd. |
934 | + * |
935 | + * This program is free software; you can redistribute it and/or modify |
936 | + * it under the terms of the GNU General Public License version 2 as |
937 | + * published by the Free Software Foundation. |
938 | + * |
939 | + * This program is distributed in the hope that it will be useful, |
940 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
941 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
942 | + * GNU General Public License for more details. |
943 | + * |
944 | + * You should have received a copy of the GNU General Public License |
945 | + * along with this program; if not, write to the Free Software |
946 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
947 | + * |
948 | + */ |
949 | + |
950 | +#ifdef HAVE_CONFIG_H |
951 | +#include <config.h> |
952 | +#endif |
953 | + |
954 | +#include <stdio.h> |
955 | +#include <string.h> |
956 | +#include <errno.h> |
957 | + |
958 | +#include <unistd.h> |
959 | +#include <fcntl.h> |
960 | +#include <sys/socket.h> |
961 | +#include <netinet/in.h> |
962 | +#include <arpa/inet.h> |
963 | +#include <netdb.h> |
964 | +#include <sys/time.h> |
965 | + |
966 | +#include <ares.h> |
967 | +#include <glib.h> |
968 | + |
969 | +#define OFONO_API_SUBJECT_TO_CHANGE |
970 | +#include <ofono/types.h> |
971 | +#include <ofono/log.h> |
972 | +#include <ofono/plugin.h> |
973 | +#include <ofono/modem.h> |
974 | +#include <ofono/dns-client.h> |
975 | + |
976 | +/* Structure representing a pending asynchronous name resolution request. */ |
977 | +struct ares_request { |
978 | + char *hostname; /* hostname that we're resolving */ |
979 | + char *interface; /* interface to use for queries */ |
980 | + struct ares_addr_node *servers; |
981 | + struct timeval timeout; /* caller-specified timeout */ |
982 | + struct timeval start_time; /* time at which request was started */ |
983 | + ofono_dns_client_callback_t cb; /* client-provided callback */ |
984 | + void *data; /* user data */ |
985 | + ares_channel channel; /* opaque, used by c-ares library */ |
986 | + GHashTable *ares_watches; /* fds that we're monitoring for c-ares */ |
987 | + guint timeout_source_id; /* glib source id for our ares timeout */ |
988 | + gboolean running; /* stopped requests are eligible for deletion */ |
989 | +}; |
990 | + |
991 | +/* |
992 | + * Structure representing a file descriptor that we're monitoring within our |
993 | + * glib event loop for c-ares. |
994 | + */ |
995 | +struct ares_watch { |
996 | + struct ares_request *request; /* backpointer to our owner */ |
997 | + int fd; /* file descriptor that we're watching */ |
998 | + GIOChannel *gio_channel; /* glib IO channel */ |
999 | + GIOCondition gio_condition; /* events in which we're interested */ |
1000 | + guint g_source_id; /* glib source id */ |
1001 | +}; |
1002 | + |
1003 | +/* |
1004 | + * List of pending asynchronous name resolution requests. We expect the number |
1005 | + * of pending requests to be small, hence the use of a linked list. |
1006 | + */ |
1007 | +static GList *pending_requests = NULL; |
1008 | + |
1009 | +/* |
1010 | + * ares requests are often stopped from within ares callbacks. In these cases, |
1011 | + * we defer deletion of the ares_request struct to the idle loop. This is the |
1012 | + * glib source id associated with the deferred deletion task. |
1013 | + */ |
1014 | +static guint deferred_deletion_g_source_id = 0; |
1015 | + |
1016 | +static void reset_ares_timeout(struct ares_request *request, |
1017 | + gboolean destroy_old_source); |
1018 | +static void stop_ares_request(struct ares_request *request); |
1019 | + |
1020 | +/*#define USE_RP_FILTER*/ |
1021 | + |
1022 | +/* |
1023 | + * Set/unset reverse path filtering (from connman). Using this should make |
1024 | + * setting routes for the DNS servers unnecessary, but unfortunately that is not |
1025 | + * happening. |
1026 | + * TODO Investigate why this is not working. |
1027 | + */ |
1028 | +#ifdef USE_RP_FILTER |
1029 | +static void rp_filter_set(const char *interface, gboolean enabled) |
1030 | +{ |
1031 | + int fd; |
1032 | + ssize_t cnt; |
1033 | + char filename[PATH_MAX]; |
1034 | + const char *str_value = (enabled == TRUE) ? "1" : "0"; |
1035 | + |
1036 | + snprintf(filename, sizeof(filename), |
1037 | + "/proc/sys/net/ipv4/conf/%s/rp_filter", interface); |
1038 | + fd = open(filename, O_WRONLY); |
1039 | + if (fd == -1) |
1040 | + return; |
1041 | + cnt = write(fd, str_value, strlen(str_value)); |
1042 | + if (cnt == -1) |
1043 | + ofono_error("%s: cannot write (%s)", __func__, strerror(errno)); |
1044 | + close(fd); |
1045 | +} |
1046 | +#else |
1047 | +static void rp_filter_set(const char *interface, gboolean enabled) |
1048 | +{ |
1049 | +} |
1050 | +#endif |
1051 | + |
1052 | +/* |
1053 | + * Callback invoked when it's time to give control back to c-ares. Controlled by |
1054 | + * the glib source referred to by |timeout_source_id| in struct ares_request. |
1055 | + */ |
1056 | +static gboolean ares_timeout_cb(gpointer data) |
1057 | +{ |
1058 | + struct ares_request *request = data; |
1059 | + const gboolean destroy_old_source = FALSE; |
1060 | + |
1061 | + DBG("request %p: running = %d", request, request->running); |
1062 | + |
1063 | + if (!request->running) { |
1064 | + request->timeout_source_id = 0; |
1065 | + return FALSE; |
1066 | + } |
1067 | + |
1068 | + ares_process_fd(request->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); |
1069 | + |
1070 | + /* |
1071 | + * NOTE: We tell reset_ares_timeout not to destroy its old timer source |
1072 | + * because we're calling it from within that source and it will be |
1073 | + * destroyed by glib when we return FALSE below. |
1074 | + */ |
1075 | + reset_ares_timeout(request, destroy_old_source); |
1076 | + |
1077 | + /* |
1078 | + * Return FALSE to get rid of our old glib source. We created a new |
1079 | + * one during our call to reset_ares_timeout above. |
1080 | + */ |
1081 | + return FALSE; |
1082 | +} |
1083 | + |
1084 | +/* |
1085 | + * Determine how long c-ares is willing to wait until being given control and |
1086 | + * schedule ares_timeout_cb to be invoked at that time. Any existing |
1087 | + * timer is replaced. If |destroy_old_source| is TRUE, the old timer's glib |
1088 | + * source will be destroyed. |
1089 | + */ |
1090 | +static void reset_ares_timeout(struct ares_request *request, |
1091 | + gboolean destroy_old_source) |
1092 | +{ |
1093 | + struct timeval ret_tv, now, elapsed, max_tv; |
1094 | + struct timeval *tv; |
1095 | + struct timeval *max = NULL; |
1096 | + guint timeout_interval_msecs = 0; |
1097 | + gboolean timeout_provided = FALSE; |
1098 | + |
1099 | + DBG("request %p: running = %d", request, request->running); |
1100 | + |
1101 | + if (!request->running) |
1102 | + return; |
1103 | + |
1104 | + /* |
1105 | + * Compute how much time has elapsed since the request started. |
1106 | + * If the client provided a non-default timeout and we've timed out, |
1107 | + * notify the client and stop the request. |
1108 | + */ |
1109 | + gettimeofday(&now, NULL); |
1110 | + timersub(&now, &request->start_time, &elapsed); |
1111 | + timeout_provided = request->timeout.tv_sec != 0 || |
1112 | + request->timeout.tv_usec != 0; |
1113 | + if (timeout_provided && timercmp(&elapsed, &request->timeout, >=)) { |
1114 | + request->cb(request->data, OFONO_DNS_CLIENT_ERROR_TIMED_OUT, |
1115 | + NULL); |
1116 | + stop_ares_request(request); |
1117 | + return; |
1118 | + } |
1119 | + |
1120 | + /* |
1121 | + * Tell c-ares how long we're willing to wait (max) and see if it wants |
1122 | + * to regain control sooner than that. |
1123 | + */ |
1124 | + if (timeout_provided) { |
1125 | + timersub(&request->timeout, &elapsed, &max_tv); |
1126 | + max = &max_tv; |
1127 | + } |
1128 | + if ((tv = ares_timeout(request->channel, max, &ret_tv)) == NULL) { |
1129 | + ofono_error("%s: ares_timeout failed", __func__); |
1130 | + return; |
1131 | + } |
1132 | + |
1133 | + /* |
1134 | + * Reschedule our timeout to be the sooner of the ares-specified tiemout |
1135 | + * and the client-specified timeout. |
1136 | + */ |
1137 | + if (request->timeout_source_id != 0 && destroy_old_source) { |
1138 | + if (!g_source_remove(request->timeout_source_id)) |
1139 | + ofono_error("%s: g_source_remove failed", __func__); |
1140 | + } |
1141 | + |
1142 | + timeout_interval_msecs = tv->tv_sec * 1000 + tv->tv_usec / 1000; |
1143 | + DBG("timeout interval = %u", timeout_interval_msecs); |
1144 | + |
1145 | + request->timeout_source_id = g_timeout_add(timeout_interval_msecs, |
1146 | + ares_timeout_cb, |
1147 | + request); |
1148 | +} |
1149 | + |
1150 | +/* |
1151 | + * Callback invoked by glib when there is activity on a file descriptor that |
1152 | + * we're monitoring for c-ares. |
1153 | + */ |
1154 | +static gboolean ares_watch_io_cb(GIOChannel *source, |
1155 | + GIOCondition condition, |
1156 | + gpointer data) |
1157 | +{ |
1158 | + struct ares_watch *watch = data; |
1159 | + ares_socket_t read_fd = ARES_SOCKET_BAD; |
1160 | + ares_socket_t write_fd = ARES_SOCKET_BAD; |
1161 | + const gboolean destroy_old_source = TRUE; |
1162 | + |
1163 | + DBG("watch %p (fd %d): condition = 0x%x", watch, watch->fd, |
1164 | + condition); |
1165 | + |
1166 | + if (!watch->request->running) { |
1167 | + /* Destroy this source by returning FALSE. */ |
1168 | + watch->g_source_id = 0; |
1169 | + return FALSE; |
1170 | + } |
1171 | + |
1172 | + if (condition & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) { |
1173 | + ofono_error("%s: error condition on fd %d", __func__, |
1174 | + watch->fd); |
1175 | + watch->g_source_id = 0; |
1176 | + return FALSE; |
1177 | + } |
1178 | + |
1179 | + if (condition & G_IO_IN) |
1180 | + read_fd = watch->fd; |
1181 | + if (condition & G_IO_OUT) |
1182 | + write_fd = watch->fd; |
1183 | + |
1184 | + /* Give control to c-ares. */ |
1185 | + ares_process_fd(watch->request->channel, read_fd, write_fd); |
1186 | + |
1187 | + reset_ares_timeout(watch->request, destroy_old_source); |
1188 | + |
1189 | + return TRUE; |
1190 | +} |
1191 | + |
1192 | +/* |
1193 | + * Destroy an ares_watch structure. We register this as our value destroy |
1194 | + * function when creating the ares_watches table, and it is called by glib |
1195 | + * whenever we remove a value from the table or destroy the table. |
1196 | + */ |
1197 | +static void destroy_ares_watch(gpointer data) |
1198 | +{ |
1199 | + struct ares_watch *watch = data; |
1200 | + |
1201 | + DBG("watch %p (fd %d)", watch, watch->fd); |
1202 | + |
1203 | + if (watch->g_source_id != 0) { |
1204 | + if (!g_source_remove(watch->g_source_id)) { |
1205 | + ofono_error("%s: g_source_remove failed for id %d", |
1206 | + __func__, watch->g_source_id); |
1207 | + } |
1208 | + watch->g_source_id = 0; |
1209 | + } |
1210 | + |
1211 | + g_io_channel_unref(watch->gio_channel); |
1212 | + g_free(watch); |
1213 | +} |
1214 | + |
1215 | +/* |
1216 | + * Create an ares_watch for |fd| and store it in the ares_watches table for |
1217 | + * |request|. Monitor for readability if |read| is TRUE. Monitor for writability |
1218 | + * if |write| is TRUE. If there is already an entry for |fd| in the table, |
1219 | + * update it according to the values of |read| and |write|. |
1220 | + */ |
1221 | +static gboolean init_ares_watch(struct ares_request *request, int fd, |
1222 | + gboolean read, gboolean write) |
1223 | +{ |
1224 | + struct ares_watch *watch; |
1225 | + |
1226 | + DBG("fd = %d, read = %d, write = %d", fd, read, write); |
1227 | + |
1228 | + /* |
1229 | + * If there's an old watch in the table, destroy it. We'll replace it |
1230 | + * with a new one below if c-ares is still interested in this fd. |
1231 | + */ |
1232 | + if (g_hash_table_lookup(request->ares_watches, &fd) != NULL) { |
1233 | + /* This removal calls destroy_ares_watch on the old watch. */ |
1234 | + g_hash_table_remove(request->ares_watches, &fd); |
1235 | + } |
1236 | + |
1237 | + if (!read && !write) |
1238 | + return TRUE; |
1239 | + |
1240 | + watch = g_malloc0(sizeof(struct ares_watch)); |
1241 | + |
1242 | + watch->request = request; |
1243 | + watch->fd = fd; |
1244 | + watch->g_source_id = 0; |
1245 | + |
1246 | + watch->gio_condition = G_IO_NVAL | G_IO_HUP | G_IO_ERR; |
1247 | + if (read) |
1248 | + watch->gio_condition |= G_IO_IN; |
1249 | + if (write) |
1250 | + watch->gio_condition |= G_IO_OUT; |
1251 | + |
1252 | + watch->gio_channel = g_io_channel_unix_new(fd); |
1253 | + if (watch->gio_channel == NULL) { |
1254 | + ofono_error("%s: could not create g_io_channel for fd %d", |
1255 | + __func__, fd); |
1256 | + g_free(watch); |
1257 | + return FALSE; |
1258 | + } |
1259 | + g_io_channel_set_close_on_unref(watch->gio_channel, FALSE); |
1260 | + |
1261 | + g_hash_table_insert(request->ares_watches, &fd, watch); |
1262 | + |
1263 | + watch->g_source_id = g_io_add_watch(watch->gio_channel, |
1264 | + watch->gio_condition, |
1265 | + ares_watch_io_cb, |
1266 | + watch); |
1267 | + |
1268 | + return TRUE; |
1269 | +} |
1270 | + |
1271 | +/* |
1272 | + * Destroy an ares_request struct, freeing the resources allocated in |
1273 | + * init_ares_request. |request| must already have been removed from the |
1274 | + * |pending_requests| list and must have been marked not running. |
1275 | + */ |
1276 | +static void destroy_ares_request(struct ares_request *request) |
1277 | +{ |
1278 | + struct ares_addr_node *node, *next; |
1279 | + |
1280 | + DBG("request %p", request); |
1281 | + |
1282 | + ares_destroy(request->channel); |
1283 | + g_free(request->hostname); |
1284 | + if (request->interface) { |
1285 | + rp_filter_set(request->interface, TRUE); |
1286 | + g_free(request->interface); |
1287 | + } |
1288 | + for (node = request->servers; node != NULL; node = next) { |
1289 | + next = node->next; |
1290 | + g_free(node); |
1291 | + } |
1292 | + if (request->timeout_source_id != 0) |
1293 | + g_source_remove(request->timeout_source_id); |
1294 | + /* Hash table destruction calls destroy_ares_watch on all watches. */ |
1295 | + g_hash_table_destroy(request->ares_watches); |
1296 | + g_free(request); |
1297 | +} |
1298 | + |
1299 | +/* |
1300 | + * Callback invoked from the main loop to perform deferred deletion of stopped |
1301 | + * ares_request objects. We do deferred deletion to avoid problems when we're in |
1302 | + * an ares callback and want to delete an object that contains context |
1303 | + * associated with that callback. |
1304 | + */ |
1305 | +static gboolean delete_stopped_ares_requests_cb(gpointer data) |
1306 | +{ |
1307 | + GList *node, *next; |
1308 | + struct ares_request *request; |
1309 | + guint num_requests_deleted = 0; |
1310 | + |
1311 | + DBG("pending_requests list has length %u", |
1312 | + g_list_length(pending_requests)); |
1313 | + |
1314 | + /* |
1315 | + * Inspect each request in |pending_requests| and destroy it if it's |
1316 | + * not running. |
1317 | + */ |
1318 | + for (node = pending_requests; node != NULL; node = next) { |
1319 | + next = g_list_next(node); |
1320 | + request = node->data; |
1321 | + if (!request->running) { |
1322 | + pending_requests = g_list_delete_link(pending_requests, |
1323 | + node); |
1324 | + destroy_ares_request(request); |
1325 | + ++num_requests_deleted; |
1326 | + } |
1327 | + } |
1328 | + DBG("deleted %u stopped requests", num_requests_deleted); |
1329 | + |
1330 | + deferred_deletion_g_source_id = 0; |
1331 | + return FALSE; |
1332 | +} |
1333 | + |
1334 | +/* |
1335 | + * Stop an ares_request and schedule the deferred deletion task if it's |
1336 | + * not already running. |
1337 | + */ |
1338 | +static void stop_ares_request(struct ares_request *request) |
1339 | +{ |
1340 | + DBG(""); |
1341 | + |
1342 | + request->running = FALSE; |
1343 | + |
1344 | + if (deferred_deletion_g_source_id != 0) |
1345 | + return; |
1346 | + |
1347 | + deferred_deletion_g_source_id = |
1348 | + g_idle_add(delete_stopped_ares_requests_cb, NULL); |
1349 | + if (deferred_deletion_g_source_id == 0) |
1350 | + ofono_error("%s: g_idle_add failed", __func__); |
1351 | +} |
1352 | + |
1353 | +/* |
1354 | + * Callback that is invoked by c-ares to tell us which sockets it wants us to |
1355 | + * monitor for readability and writability. |
1356 | + */ |
1357 | +static void ares_socket_state_cb(void *data, int s, int read, int write) |
1358 | +{ |
1359 | + struct ares_request *request = (struct ares_request *) data; |
1360 | + |
1361 | + DBG(""); |
1362 | + |
1363 | + if (!request->running) |
1364 | + return; |
1365 | + |
1366 | + DBG("socket %d: read = %d, write = %d", s, read, write); |
1367 | + |
1368 | + if (!init_ares_watch(request, s, read, write)) |
1369 | + ofono_error("%s: couldn't create ares_watch for socket %d", |
1370 | + __func__, s); |
1371 | +} |
1372 | + |
1373 | +/* |
1374 | + * Converts a c-ares status code to the corresponding dns_client status code. |
1375 | + * We do this to completely encapsulate c-ares. In theory, we should be able to |
1376 | + * replace it with a different asynchronous DNS library without changing our |
1377 | + * clients. |
1378 | + */ |
1379 | +static ofono_dns_client_status_t status_from_ares_status(int ares_status) |
1380 | +{ |
1381 | + switch(ares_status) { |
1382 | + case ARES_SUCCESS: |
1383 | + return OFONO_DNS_CLIENT_SUCCESS; |
1384 | + case ARES_ENODATA: |
1385 | + return OFONO_DNS_CLIENT_ERROR_NO_DATA; |
1386 | + case ARES_EFORMERR: |
1387 | + return OFONO_DNS_CLIENT_ERROR_FORM_ERR; |
1388 | + case ARES_ESERVFAIL: |
1389 | + return OFONO_DNS_CLIENT_ERROR_SERVER_FAIL; |
1390 | + case ARES_ENOTFOUND: |
1391 | + return OFONO_DNS_CLIENT_ERROR_NOT_FOUND; |
1392 | + case ARES_ENOTIMP: |
1393 | + return OFONO_DNS_CLIENT_ERROR_NOT_IMP; |
1394 | + case ARES_EREFUSED: |
1395 | + return OFONO_DNS_CLIENT_ERROR_REFUSED; |
1396 | + case ARES_EBADQUERY: |
1397 | + case ARES_EBADNAME: |
1398 | + case ARES_EBADFAMILY: |
1399 | + case ARES_EBADRESP: |
1400 | + return OFONO_DNS_CLIENT_ERROR_BAD_QUERY; |
1401 | + case ARES_ECONNREFUSED: |
1402 | + return OFONO_DNS_CLIENT_ERROR_NET_REFUSED; |
1403 | + case ARES_ETIMEOUT: |
1404 | + return OFONO_DNS_CLIENT_ERROR_TIMED_OUT; |
1405 | + default: |
1406 | + return OFONO_DNS_CLIENT_ERROR_UNKNOWN; |
1407 | + } |
1408 | +} |
1409 | + |
1410 | +/* |
1411 | + * Callback that is invoked by c-ares when an asynchronous name resolution |
1412 | + * request that we have previously initiated is complete. |
1413 | + */ |
1414 | +static void ares_request_cb(void *arg, int ares_status, int timeouts, |
1415 | + struct hostent *hostent) |
1416 | +{ |
1417 | + struct sockaddr_in sin; |
1418 | + struct sockaddr_in6 sin6; |
1419 | + int addr_length; |
1420 | + void *addr_buffer; |
1421 | + char ip_addr_string[INET6_ADDRSTRLEN]; |
1422 | + struct sockaddr *ip_addr; |
1423 | + struct ares_request *request = (struct ares_request *)arg; |
1424 | + |
1425 | + DBG(""); |
1426 | + |
1427 | + if (!request->running) |
1428 | + return; |
1429 | + |
1430 | + /* Stop the request. It will be deleted later from the idle loop. */ |
1431 | + stop_ares_request(request); |
1432 | + |
1433 | + if (ares_status != ARES_SUCCESS) { |
1434 | + DBG("ares request for '%s' failed: %s", |
1435 | + request->hostname, ares_strerror(ares_status)); |
1436 | + /* Notify client. */ |
1437 | + request->cb(request->data, status_from_ares_status(ares_status), |
1438 | + NULL); |
1439 | + return; |
1440 | + } |
1441 | + |
1442 | + if (hostent->h_addrtype != AF_INET && hostent->h_addrtype != AF_INET6) { |
1443 | + ofono_error("%s: unsupported addrtype: %d", |
1444 | + __func__, hostent->h_addrtype); |
1445 | + request->cb(request->data, OFONO_DNS_CLIENT_ERROR_NO_DATA, |
1446 | + NULL); |
1447 | + return; |
1448 | + } |
1449 | + |
1450 | + if (hostent->h_addrtype == AF_INET) { |
1451 | + memset(&sin, 0, sizeof(sin)); |
1452 | + sin.sin_family = AF_INET; |
1453 | + addr_length = sizeof(sin.sin_addr.s_addr); |
1454 | + addr_buffer = &sin.sin_addr.s_addr; |
1455 | + ip_addr = (struct sockaddr *) &sin; |
1456 | + } else { /* AF_INET6 */ |
1457 | + memset(&sin6, 0, sizeof(sin6)); |
1458 | + sin6.sin6_family = AF_INET6; |
1459 | + addr_length = sizeof(sin6.sin6_addr.s6_addr); |
1460 | + addr_buffer = &sin6.sin6_addr.s6_addr; |
1461 | + ip_addr = (struct sockaddr *) &sin6; |
1462 | + } |
1463 | + |
1464 | + if (hostent->h_length > addr_length) { |
1465 | + ofono_error("%s: address too large: %u bytes", |
1466 | + __func__, hostent->h_length); |
1467 | + request->cb(request->data, OFONO_DNS_CLIENT_ERROR_NO_DATA, |
1468 | + NULL); |
1469 | + return; |
1470 | + } |
1471 | + |
1472 | + memcpy(addr_buffer, hostent->h_addr, hostent->h_length); |
1473 | + |
1474 | + if (inet_ntop(hostent->h_addrtype, addr_buffer, ip_addr_string, |
1475 | + sizeof(ip_addr_string)) == NULL) { |
1476 | + ofono_error("%s: could not convert address to string: %s", |
1477 | + __func__, strerror(errno)); |
1478 | + request->cb(request->data, OFONO_DNS_CLIENT_ERROR_NO_DATA, |
1479 | + NULL); |
1480 | + return; |
1481 | + } |
1482 | + |
1483 | + DBG("ares request for '%s' succeeded with %d timeouts: %s", |
1484 | + request->hostname, timeouts, ip_addr_string); |
1485 | + request->cb(request->data, status_from_ares_status(ares_status), |
1486 | + ip_addr); |
1487 | +} |
1488 | + |
1489 | +/* Cancel all in-progress asynchronous name resolution requests. */ |
1490 | +static void cancel_all_ares_requests() |
1491 | +{ |
1492 | + GList *node; |
1493 | + struct ares_request *request; |
1494 | + |
1495 | + DBG(""); |
1496 | + |
1497 | + while ((node = g_list_first(pending_requests)) != NULL) { |
1498 | + request = node->data; |
1499 | + pending_requests = g_list_delete_link(pending_requests, node); |
1500 | + request->running = FALSE; /* don't trip assertion */ |
1501 | + destroy_ares_request(request); |
1502 | + } |
1503 | +} |
1504 | + |
1505 | +static void set_request_servers(const char **servers, |
1506 | + struct ares_request *request) |
1507 | +{ |
1508 | + struct ares_addr_node *current; |
1509 | + struct ares_addr_node **prev = &request->servers; |
1510 | + const char **dns; |
1511 | + int rc; |
1512 | + |
1513 | + for (dns = servers; *dns != NULL; ++dns) { |
1514 | + current = g_malloc0(sizeof(*current)); |
1515 | + rc = inet_pton(AF_INET, *dns, ¤t->addr.addr4); |
1516 | + if (rc == 1) { |
1517 | + current->family = AF_INET; |
1518 | + } else { |
1519 | + rc = inet_pton(AF_INET6, *dns, ¤t->addr.addr6); |
1520 | + if (rc != 1) { |
1521 | + ofono_error("%s: wrong dns address %s", |
1522 | + __func__, *dns); |
1523 | + g_free(current); |
1524 | + continue; |
1525 | + } |
1526 | + current->family = AF_INET6; |
1527 | + } |
1528 | + |
1529 | + *prev = current; |
1530 | + prev = ¤t->next; |
1531 | + } |
1532 | +} |
1533 | + |
1534 | +/* Initiate an asynchronous name resolution request. */ |
1535 | +static ofono_dns_client_request_t |
1536 | +ofono_dns_client_submit_request(const char *hostname, |
1537 | + const char *interface, |
1538 | + const char **servers, |
1539 | + int timeout_ms, |
1540 | + ofono_dns_client_callback_t cb, |
1541 | + void *data) |
1542 | +{ |
1543 | + int ares_status; |
1544 | + struct ares_request *request; |
1545 | + struct ares_options options; |
1546 | + int optmask; |
1547 | + const gboolean destroy_old_source = TRUE; |
1548 | + |
1549 | + DBG(""); |
1550 | + |
1551 | + if (timeout_ms < 0) { |
1552 | + DBG("invalid timeout value of %d ms", timeout_ms); |
1553 | + return NULL; |
1554 | + } |
1555 | + |
1556 | + request = g_malloc0(sizeof(struct ares_request)); |
1557 | + request->running = TRUE; |
1558 | + |
1559 | + request->ares_watches = g_hash_table_new_full(g_int_hash, g_int_equal, |
1560 | + NULL, destroy_ares_watch); |
1561 | + if (request->ares_watches == NULL) { |
1562 | + ofono_error("%s: could not create ares_watches table", |
1563 | + __func__); |
1564 | + g_free(request); |
1565 | + return NULL; |
1566 | + } |
1567 | + |
1568 | + /* |
1569 | + * Init a c-ares channel for this request. We set an option asking |
1570 | + * c-ares to notify us via callback about which sockets it wants to |
1571 | + * monitor for readability and writability. This allows us to |
1572 | + * integrate c-ares activity into our glib main event loop. |
1573 | + */ |
1574 | + memset(&options, 0, sizeof(options)); |
1575 | + options.sock_state_cb = ares_socket_state_cb; |
1576 | + options.sock_state_cb_data = request; |
1577 | + optmask = ARES_OPT_SOCK_STATE_CB; |
1578 | + if (timeout_ms > 0) { |
1579 | + options.timeout = timeout_ms; |
1580 | + optmask |= ARES_OPT_TIMEOUTMS; |
1581 | + } |
1582 | + ares_status = ares_init_options(&request->channel, &options, optmask); |
1583 | + if (ares_status != ARES_SUCCESS) { |
1584 | + ofono_error("%s: failed to init c-ares channel: %s", __func__, |
1585 | + ares_strerror(ares_status)); |
1586 | + request->running = FALSE; /* don't trip assertion */ |
1587 | + g_hash_table_destroy(request->ares_watches); |
1588 | + g_free(request); |
1589 | + return NULL; |
1590 | + } |
1591 | + |
1592 | + if (servers != NULL) { |
1593 | + set_request_servers(servers, request); |
1594 | + ares_status = |
1595 | + ares_set_servers(request->channel, request->servers); |
1596 | + /* Log an error, but continue anyway */ |
1597 | + if (ares_status != ARES_SUCCESS) |
1598 | + ofono_error("%s: failed to set name servers: %s", |
1599 | + __func__, ares_strerror(ares_status)); |
1600 | + } |
1601 | + |
1602 | + /* |
1603 | + * If the caller has provided a preferred interface, tell c-ares to |
1604 | + * send requests out that interface, and unset rf filter. |
1605 | + */ |
1606 | + if (interface != NULL) { |
1607 | + DBG("caller has specified device %s", interface); |
1608 | + |
1609 | + request->interface = g_strdup(interface); |
1610 | + ares_set_local_dev(request->channel, request->interface); |
1611 | + rp_filter_set(request->interface, FALSE); |
1612 | + } |
1613 | + |
1614 | + request->cb = cb; |
1615 | + request->data = data; |
1616 | + request->hostname = g_strdup(hostname); |
1617 | + request->timeout.tv_sec = timeout_ms / 1000; |
1618 | + request->timeout.tv_usec = (timeout_ms % 1000) * 1000; |
1619 | + gettimeofday(&request->start_time, NULL); |
1620 | + |
1621 | + pending_requests = g_list_append(pending_requests, request); |
1622 | + |
1623 | + ares_gethostbyname(request->channel, hostname, AF_INET, |
1624 | + ares_request_cb, request); |
1625 | + |
1626 | + reset_ares_timeout(request, destroy_old_source); |
1627 | + |
1628 | + return request; |
1629 | +} |
1630 | + |
1631 | +/* Cancel an in-progress name resolution request. */ |
1632 | +static gboolean ofono_dns_client_cancel_request(ofono_dns_client_request_t req) |
1633 | +{ |
1634 | + struct ares_request *request = req; |
1635 | + |
1636 | + if (request == NULL || g_list_find (pending_requests, request) == NULL) |
1637 | + return FALSE; |
1638 | + |
1639 | + DBG("request %p", request); |
1640 | + |
1641 | + if (!request->running) |
1642 | + return TRUE; |
1643 | + |
1644 | + pending_requests = g_list_remove(pending_requests, request); |
1645 | + request->running = FALSE; /* don't trip assertion */ |
1646 | + destroy_ares_request(request); |
1647 | + |
1648 | + return TRUE; |
1649 | +} |
1650 | + |
1651 | +static struct ofono_dns_client_driver dns_driver = { |
1652 | + .name = "c-ares DNS client", |
1653 | + .submit_request = ofono_dns_client_submit_request, |
1654 | + .cancel_request = ofono_dns_client_cancel_request |
1655 | +}; |
1656 | + |
1657 | +/* Intitialize this module. */ |
1658 | +static int c_ares_init(void) |
1659 | +{ |
1660 | + int ares_status = 0; |
1661 | + DBG(""); |
1662 | + ares_status = ares_library_init(ARES_LIB_INIT_ALL); |
1663 | + if (ares_status != ARES_SUCCESS) { |
1664 | + ofono_error("%s: Failed to init c-ares: %s", __func__, |
1665 | + ares_strerror(ares_status)); |
1666 | + return -1; |
1667 | + } |
1668 | + return ofono_dns_client_driver_register(&dns_driver); |
1669 | +} |
1670 | + |
1671 | +/* Clean up. */ |
1672 | +static void c_ares_exit(void) |
1673 | +{ |
1674 | + DBG(""); |
1675 | + |
1676 | + ofono_dns_client_driver_unregister(&dns_driver); |
1677 | + |
1678 | + if (deferred_deletion_g_source_id != 0) { |
1679 | + g_source_remove(deferred_deletion_g_source_id); |
1680 | + deferred_deletion_g_source_id = 0; |
1681 | + } |
1682 | + cancel_all_ares_requests(); |
1683 | + ares_library_cleanup(); |
1684 | +} |
1685 | + |
1686 | +OFONO_PLUGIN_DEFINE(c_ares_dns_client, "c-ares DNS client", VERSION, |
1687 | + OFONO_PLUGIN_PRIORITY_DEFAULT, |
1688 | + c_ares_init, c_ares_exit) |
1689 | |
1690 | === modified file 'plugins/mtk.c' |
1691 | --- plugins/mtk.c 2015-04-01 07:04:18 +0000 |
1692 | +++ plugins/mtk.c 2015-07-02 17:01:42 +0000 |
1693 | @@ -830,9 +830,9 @@ |
1694 | struct ofono_gprs_context *gc; |
1695 | struct ril_gprs_driver_data gprs_data = { md->ril, modem }; |
1696 | struct ril_gprs_context_data inet_ctx = |
1697 | - { md->ril, OFONO_GPRS_CONTEXT_TYPE_INTERNET }; |
1698 | + { md->ril, modem, OFONO_GPRS_CONTEXT_TYPE_INTERNET }; |
1699 | struct ril_gprs_context_data mms_ctx = |
1700 | - { md->ril, OFONO_GPRS_CONTEXT_TYPE_MMS }; |
1701 | + { md->ril, modem, OFONO_GPRS_CONTEXT_TYPE_MMS }; |
1702 | |
1703 | DBG("SIM ready, creating more atoms"); |
1704 | |
1705 | @@ -1347,6 +1347,16 @@ |
1706 | mtk_set_online(mtk_data_1->modem, FALSE, set_offline_cb, NULL); |
1707 | } |
1708 | |
1709 | +void mtk_reset_modem(struct ofono_modem *modem) |
1710 | +{ |
1711 | + |
1712 | + if (ofono_modem_get_powered(modem) == FALSE) |
1713 | + return; |
1714 | + |
1715 | + ofono_modem_set_powered(modem, FALSE); |
1716 | + g_idle_add(mtk_connected, modem); |
1717 | +} |
1718 | + |
1719 | static void create_atoms_on_connection(struct ofono_modem *modem) |
1720 | { |
1721 | struct mtk_data *md = ofono_modem_get_data(modem); |
1722 | |
1723 | === modified file 'plugins/ril.c' |
1724 | --- plugins/ril.c 2015-02-04 00:09:22 +0000 |
1725 | +++ plugins/ril.c 2015-07-02 17:01:42 +0000 |
1726 | @@ -63,6 +63,7 @@ |
1727 | #include "ril.h" |
1728 | #include "drivers/rilmodem/rilmodem.h" |
1729 | #include "drivers/rilmodem/vendor.h" |
1730 | +#include "drivers/qcommsimmodem/qcom_msim_modem.h" |
1731 | |
1732 | #define MAX_SIM_STATUS_RETRIES 15 |
1733 | |
1734 | @@ -70,7 +71,8 @@ |
1735 | #define RILD_MAX_CONNECT_RETRIES 5 |
1736 | #define RILD_CONNECT_RETRY_TIME_S 5 |
1737 | |
1738 | -#define RILD_CMD_SOCKET "/dev/socket/rild" |
1739 | +char *RILD_CMD_SOCKET[] = {"/dev/socket/rild", "/dev/socket/rild1"}; |
1740 | +char *GRIL_HEX_PREFIX[] = {"Device 0: ", "Device 1: "}; |
1741 | |
1742 | struct ril_data { |
1743 | GRil *ril; |
1744 | @@ -111,11 +113,19 @@ |
1745 | case RADIO_STATE_ON: |
1746 | |
1747 | if (rd->radio_settings == NULL) { |
1748 | + char *rs_driver; |
1749 | struct ril_radio_settings_driver_data rs_data = |
1750 | { rd->ril, modem }; |
1751 | + |
1752 | + if (rd->vendor == OFONO_RIL_VENDOR_QCOM_MSIM) |
1753 | + rs_driver = QCOMMSIMMODEM; |
1754 | + else |
1755 | + rs_driver = RILMODEM; |
1756 | + |
1757 | rd->radio_settings = |
1758 | ofono_radio_settings_create(modem, |
1759 | - rd->vendor, RILMODEM, &rs_data); |
1760 | + rd->vendor, rs_driver, |
1761 | + &rs_data); |
1762 | } |
1763 | |
1764 | break; |
1765 | @@ -215,9 +225,9 @@ |
1766 | struct ofono_message_waiting *mw; |
1767 | struct ril_gprs_driver_data gprs_data = { rd->ril, modem }; |
1768 | struct ril_gprs_context_data inet_ctx = |
1769 | - { rd->ril, OFONO_GPRS_CONTEXT_TYPE_INTERNET }; |
1770 | + { rd->ril, modem, OFONO_GPRS_CONTEXT_TYPE_INTERNET }; |
1771 | struct ril_gprs_context_data mms_ctx = |
1772 | - { rd->ril, OFONO_GPRS_CONTEXT_TYPE_MMS }; |
1773 | + { rd->ril, modem, OFONO_GPRS_CONTEXT_TYPE_MMS }; |
1774 | |
1775 | /* TODO: this function should setup: |
1776 | * - phonebook |
1777 | @@ -337,8 +347,11 @@ |
1778 | static int create_gril(struct ofono_modem *modem) |
1779 | { |
1780 | struct ril_data *rd = ofono_modem_get_data(modem); |
1781 | + int slot_id = ofono_modem_get_integer(modem, "Slot"); |
1782 | |
1783 | - rd->ril = g_ril_new(RILD_CMD_SOCKET, OFONO_RIL_VENDOR_AOSP); |
1784 | + ofono_info("Using %s as socket for slot %d.", |
1785 | + RILD_CMD_SOCKET[slot_id], slot_id); |
1786 | + rd->ril = g_ril_new(RILD_CMD_SOCKET[slot_id], OFONO_RIL_VENDOR_AOSP); |
1787 | |
1788 | /* NOTE: Since AT modems open a tty, and then call |
1789 | * g_at_chat_new(), they're able to return -EIO if |
1790 | @@ -352,12 +365,13 @@ |
1791 | ofono_error("g_ril_new() failed to create modem!"); |
1792 | return -EIO; |
1793 | } |
1794 | + g_ril_set_slot(rd->ril, slot_id); |
1795 | |
1796 | if (getenv("OFONO_RIL_TRACE")) |
1797 | g_ril_set_trace(rd->ril, TRUE); |
1798 | |
1799 | if (getenv("OFONO_RIL_HEX_TRACE")) |
1800 | - g_ril_set_debugf(rd->ril, ril_debug, "Device: "); |
1801 | + g_ril_set_debugf(rd->ril, ril_debug, GRIL_HEX_PREFIX[slot_id]); |
1802 | |
1803 | g_ril_register(rd->ril, RIL_UNSOL_RIL_CONNECTED, |
1804 | ril_connected, modem); |
1805 | |
1806 | === added file 'src/dns-client.c' |
1807 | --- src/dns-client.c 1970-01-01 00:00:00 +0000 |
1808 | +++ src/dns-client.c 2015-07-02 17:01:42 +0000 |
1809 | @@ -0,0 +1,128 @@ |
1810 | +/* |
1811 | + * |
1812 | + * oFono - Open Source Telephony |
1813 | + * |
1814 | + * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
1815 | + * Copyright (C) 2015 Canonical Ltd. |
1816 | + * |
1817 | + * This program is free software; you can redistribute it and/or modify |
1818 | + * it under the terms of the GNU General Public License version 2 as |
1819 | + * published by the Free Software Foundation. |
1820 | + * |
1821 | + * This program is distributed in the hope that it will be useful, |
1822 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1823 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1824 | + * GNU General Public License for more details. |
1825 | + * |
1826 | + * You should have received a copy of the GNU General Public License |
1827 | + * along with this program; if not, write to the Free Software |
1828 | + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
1829 | + * |
1830 | + */ |
1831 | + |
1832 | +#ifdef HAVE_CONFIG_H |
1833 | +#include <config.h> |
1834 | +#endif |
1835 | + |
1836 | +#include <errno.h> |
1837 | +#include <string.h> |
1838 | +#include <glib.h> |
1839 | +#include "ofono.h" |
1840 | +#include "dns-client.h" |
1841 | + |
1842 | +static GSList *g_drivers = NULL; |
1843 | + |
1844 | +ofono_dns_client_request_t __ofono_dns_client_submit_request( |
1845 | + const char *hostname, |
1846 | + const char *device, |
1847 | + const char **servers, |
1848 | + int timeout_ms, |
1849 | + ofono_dns_client_callback_t cb, |
1850 | + void *data) |
1851 | +{ |
1852 | + GSList *d; |
1853 | + ofono_dns_client_request_t token = NULL; |
1854 | + |
1855 | + for (d = g_drivers; d != NULL; d = d->next) { |
1856 | + const struct ofono_dns_client_driver *driver = d->data; |
1857 | + |
1858 | + if (driver->submit_request == NULL) |
1859 | + continue; |
1860 | + |
1861 | + DBG("Calling dns client plugin '%s'", driver->name); |
1862 | + |
1863 | + if ((token = driver->submit_request(hostname, device, servers, |
1864 | + timeout_ms, cb, data)) == NULL) |
1865 | + continue; |
1866 | + |
1867 | + return token; |
1868 | + } |
1869 | + |
1870 | + return token; |
1871 | +} |
1872 | + |
1873 | +void __ofono_dns_client_cancel_request(ofono_dns_client_request_t request) |
1874 | +{ |
1875 | + GSList *d; |
1876 | + |
1877 | + for (d = g_drivers; d != NULL; d = d->next) { |
1878 | + const struct ofono_dns_client_driver *driver = d->data; |
1879 | + |
1880 | + if (driver->cancel_request == NULL) |
1881 | + continue; |
1882 | + |
1883 | + /* Returns TRUE if this driver is the request owner */ |
1884 | + if (driver->cancel_request(request)) |
1885 | + break; |
1886 | + } |
1887 | +} |
1888 | + |
1889 | +/* |
1890 | + * Returns a human-friendly error string corresponding to |status|. |
1891 | + * The strings that we return are intentionally consistent with shill error |
1892 | + * messages. |
1893 | + */ |
1894 | +const char *__ofono_dns_client_strerror(ofono_dns_client_status_t status) |
1895 | +{ |
1896 | + switch(status) { |
1897 | + case OFONO_DNS_CLIENT_SUCCESS: |
1898 | + return "The query was successful."; |
1899 | + case OFONO_DNS_CLIENT_ERROR_NO_DATA: |
1900 | + return "The query response contains no answers."; |
1901 | + case OFONO_DNS_CLIENT_ERROR_FORM_ERR: |
1902 | + return "The server says the query is bad."; |
1903 | + case OFONO_DNS_CLIENT_ERROR_SERVER_FAIL: |
1904 | + return "The server says it had a failure."; |
1905 | + case OFONO_DNS_CLIENT_ERROR_NOT_FOUND: |
1906 | + return "The queried-for domain was not found."; |
1907 | + case OFONO_DNS_CLIENT_ERROR_NOT_IMP: |
1908 | + return "The server doesn't implement operation."; |
1909 | + case OFONO_DNS_CLIENT_ERROR_REFUSED: |
1910 | + return "The server replied, refused the query."; |
1911 | + case OFONO_DNS_CLIENT_ERROR_BAD_QUERY: |
1912 | + return "Locally we could not format a query."; |
1913 | + case OFONO_DNS_CLIENT_ERROR_NET_REFUSED: |
1914 | + return "The network connection was refused."; |
1915 | + case OFONO_DNS_CLIENT_ERROR_TIMED_OUT: |
1916 | + return "The network connection was timed out."; |
1917 | + case OFONO_DNS_CLIENT_ERROR_UNKNOWN: |
1918 | + default: |
1919 | + return "DNS Resolver unknown internal error."; |
1920 | + } |
1921 | +} |
1922 | + |
1923 | +int ofono_dns_client_driver_register(struct ofono_dns_client_driver *driver) |
1924 | +{ |
1925 | + DBG("driver: %p name: %s", driver, driver->name); |
1926 | + |
1927 | + g_drivers = g_slist_prepend(g_drivers, driver); |
1928 | + return 0; |
1929 | +} |
1930 | + |
1931 | +void ofono_dns_client_driver_unregister( |
1932 | + const struct ofono_dns_client_driver *driver) |
1933 | +{ |
1934 | + DBG("driver: %p name: %s", driver, driver->name); |
1935 | + |
1936 | + g_drivers = g_slist_remove(g_drivers, driver); |
1937 | +} |
1938 | |
1939 | === modified file 'src/gprs.c' |
1940 | --- src/gprs.c 2015-05-20 16:32:09 +0000 |
1941 | +++ src/gprs.c 2015-07-02 17:01:42 +0000 |
1942 | @@ -35,6 +35,8 @@ |
1943 | #include <net/route.h> |
1944 | #include <netinet/in.h> |
1945 | #include <arpa/inet.h> |
1946 | +#include <resolv.h> |
1947 | +#include <netdb.h> |
1948 | |
1949 | #include <glib.h> |
1950 | #include <gdbus.h> |
1951 | @@ -46,6 +48,7 @@ |
1952 | #include "idmap.h" |
1953 | #include "simutil.h" |
1954 | #include "util.h" |
1955 | +#include "dns-client.h" |
1956 | |
1957 | #define GPRS_FLAG_ATTACHING 0x1 |
1958 | #define GPRS_FLAG_RECHECK 0x2 |
1959 | @@ -58,6 +61,7 @@ |
1960 | #define MAX_MESSAGE_CENTER_LENGTH 255 |
1961 | #define MAX_CONTEXTS 256 |
1962 | #define SUSPEND_TIMEOUT 8 |
1963 | +#define DNS_LOOKUP_TOUT_MS 15000 |
1964 | |
1965 | struct ofono_gprs { |
1966 | GSList *contexts; |
1967 | @@ -97,6 +101,7 @@ |
1968 | char *gateway; |
1969 | char **dns; |
1970 | char *proxy; |
1971 | + uint16_t proxy_port; |
1972 | }; |
1973 | |
1974 | struct ipv6_settings { |
1975 | @@ -138,6 +143,7 @@ |
1976 | struct ofono_gprs_primary_context context; |
1977 | struct ofono_gprs_context *context_driver; |
1978 | struct ofono_gprs *gprs; |
1979 | + ofono_dns_client_request_t lookup_req; |
1980 | }; |
1981 | |
1982 | static void gprs_netreg_update(struct ofono_gprs *gprs); |
1983 | @@ -377,11 +383,11 @@ |
1984 | ofono_dbus_dict_append(&array, "Interface", |
1985 | DBUS_TYPE_STRING, &settings->interface); |
1986 | |
1987 | - /* If we have a Proxy, no other settings are relevant */ |
1988 | if (settings->ipv4->proxy) { |
1989 | ofono_dbus_dict_append(&array, "Proxy", DBUS_TYPE_STRING, |
1990 | &settings->ipv4->proxy); |
1991 | - goto done; |
1992 | + ofono_dbus_dict_append(&array, "ProxyPort", DBUS_TYPE_UINT16, |
1993 | + &settings->ipv4->proxy_port); |
1994 | } |
1995 | |
1996 | if (settings->ipv4->static_ip == TRUE) |
1997 | @@ -536,9 +542,183 @@ |
1998 | context_settings_append_ipv6); |
1999 | } |
2000 | |
2001 | -static void pri_parse_proxy(struct pri_context *ctx, const char *proxy) |
2002 | -{ |
2003 | - char *scheme, *host, *port, *path; |
2004 | +static void set_route(const struct context_settings *settings, |
2005 | + const char *ipstr, gboolean create) |
2006 | +{ |
2007 | + struct rtentry rt; |
2008 | + struct sockaddr_in addr; |
2009 | + int sk; |
2010 | + const char *debug_str = create ? "create" : "remove"; |
2011 | + |
2012 | + /* TODO Handle IPv6 case */ |
2013 | + |
2014 | + DBG("%s for %s", ipstr, debug_str); |
2015 | + |
2016 | + if (settings->interface == NULL) |
2017 | + return; |
2018 | + |
2019 | + sk = socket(PF_INET, SOCK_DGRAM, 0); |
2020 | + if (sk < 0) |
2021 | + return; |
2022 | + |
2023 | + memset(&rt, 0, sizeof(rt)); |
2024 | + rt.rt_dev = (char *) settings->interface; |
2025 | + rt.rt_flags = RTF_HOST; |
2026 | + |
2027 | + if (create) |
2028 | + rt.rt_flags |= RTF_UP; |
2029 | + |
2030 | + memset(&addr, 0, sizeof(addr)); |
2031 | + addr.sin_family = AF_INET; |
2032 | + addr.sin_addr.s_addr = inet_addr(ipstr); |
2033 | + if (addr.sin_addr.s_addr == INADDR_NONE) { |
2034 | + ofono_error("Cannot %s route for invalid IP %s", |
2035 | + debug_str, ipstr); |
2036 | + return; |
2037 | + } |
2038 | + memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst)); |
2039 | + |
2040 | + memset(&addr, 0, sizeof(addr)); |
2041 | + addr.sin_family = AF_INET; |
2042 | + addr.sin_addr.s_addr = INADDR_ANY; |
2043 | + memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway)); |
2044 | + memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask)); |
2045 | + |
2046 | + if (ioctl(sk, create ? SIOCADDRT : SIOCDELRT, &rt) < 0) |
2047 | + ofono_error("Failed to %s proxy host route: %s (%d)", |
2048 | + debug_str, strerror(errno), errno); |
2049 | + |
2050 | + close(sk); |
2051 | +} |
2052 | + |
2053 | +static void pri_activate_finish(struct pri_context *ctx) |
2054 | +{ |
2055 | + struct ofono_gprs_context *gc = ctx->context_driver; |
2056 | + struct context_settings *settings = gc->settings; |
2057 | + DBusConnection *conn = ofono_dbus_get_connection(); |
2058 | + dbus_bool_t value; |
2059 | + |
2060 | + DBG("proxy %s port %u", ctx->proxy_host ? ctx->proxy_host : "NULL", |
2061 | + ctx->proxy_port); |
2062 | + |
2063 | + if (ctx->proxy_host) { |
2064 | + settings->ipv4->proxy = g_strdup(ctx->proxy_host); |
2065 | + settings->ipv4->proxy_port = ctx->proxy_port; |
2066 | + |
2067 | + if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_MMS) |
2068 | + set_route(settings, ctx->proxy_host, TRUE); |
2069 | + } |
2070 | + |
2071 | + ctx->active = TRUE; |
2072 | + __ofono_dbus_pending_reply(&ctx->pending, |
2073 | + dbus_message_new_method_return(ctx->pending)); |
2074 | + |
2075 | + if (gc->settings->interface != NULL) |
2076 | + pri_context_signal_settings(ctx, settings->ipv4 != NULL, |
2077 | + settings->ipv6 != NULL); |
2078 | + |
2079 | + value = ctx->active; |
2080 | + ofono_dbus_signal_property_changed(conn, ctx->path, |
2081 | + OFONO_CONNECTION_CONTEXT_INTERFACE, |
2082 | + "Active", DBUS_TYPE_BOOLEAN, &value); |
2083 | +} |
2084 | + |
2085 | +static void clean_dns_routes(struct pri_context *ctx) |
2086 | +{ |
2087 | + struct context_settings *settings = ctx->context_driver->settings; |
2088 | + int i; |
2089 | + |
2090 | + for (i = 0; settings->ipv4->dns[i] != NULL; ++i) |
2091 | + set_route(settings, settings->ipv4->dns[i], FALSE); |
2092 | +} |
2093 | + |
2094 | +static void lookup_address_cb(void *data, ofono_dns_client_status_t status, |
2095 | + struct sockaddr *ip_addr) |
2096 | +{ |
2097 | + struct pri_context *ctx = data; |
2098 | + char str[INET_ADDRSTRLEN]; |
2099 | + |
2100 | + if (status == OFONO_DNS_CLIENT_SUCCESS) { |
2101 | + void *addr; |
2102 | + |
2103 | + if (ip_addr->sa_family == AF_INET) { |
2104 | + struct sockaddr_in *ip4 = (void *) ip_addr; |
2105 | + addr = &ip4->sin_addr; |
2106 | + } else { |
2107 | + /* Assume ipv6 */ |
2108 | + struct sockaddr_in6 *ip6 = (void *) ip_addr; |
2109 | + addr = &ip6->sin6_addr; |
2110 | + } |
2111 | + |
2112 | + if (inet_ntop(ip_addr->sa_family, addr, str, sizeof(str))) |
2113 | + ctx->proxy_host = g_strdup(str); |
2114 | + else |
2115 | + ofono_error("%s: Cannot convert type %d to address", |
2116 | + __func__, ip_addr->sa_family); |
2117 | + } else { |
2118 | + ofono_error("DNS error %s", |
2119 | + __ofono_dns_client_strerror(status)); |
2120 | + } |
2121 | + |
2122 | + ctx->lookup_req = NULL; |
2123 | + |
2124 | + clean_dns_routes(ctx); |
2125 | + pri_activate_finish(ctx); |
2126 | +} |
2127 | + |
2128 | +static void lookup_address(struct pri_context *ctx, const char *proxy) |
2129 | +{ |
2130 | + struct context_settings *settings = ctx->context_driver->settings; |
2131 | + |
2132 | + DBG("hostname is %s", proxy); |
2133 | + |
2134 | + ctx->lookup_req = __ofono_dns_client_submit_request( |
2135 | + proxy, settings->interface, |
2136 | + (const char **) settings->ipv4->dns, |
2137 | + DNS_LOOKUP_TOUT_MS, |
2138 | + lookup_address_cb, ctx); |
2139 | + if (ctx->lookup_req == NULL) |
2140 | + clean_dns_routes(ctx); |
2141 | +} |
2142 | + |
2143 | +static void get_proxy_ip(struct pri_context *ctx, const char *host) |
2144 | +{ |
2145 | + struct context_settings *settings = ctx->context_driver->settings; |
2146 | + struct in_addr addr; |
2147 | + int i; |
2148 | + |
2149 | + if (inet_pton(AF_INET, host, &addr) == 1) { |
2150 | + ctx->proxy_host = g_strdup(host); |
2151 | + return; |
2152 | + } |
2153 | + |
2154 | + /* Not an IP -> use DNS if possible */ |
2155 | + |
2156 | + if (settings->ipv4 == NULL || settings->ipv4->dns == NULL || |
2157 | + settings->ipv4->dns[0] == NULL) { |
2158 | + ofono_error("No DNS to find IP for MMS proxy/MMSC %s", host); |
2159 | + return; |
2160 | + } |
2161 | + |
2162 | + for (i = 0; settings->ipv4->dns[i] != NULL; ++i) |
2163 | + set_route(settings, settings->ipv4->dns[i], TRUE); |
2164 | + |
2165 | + lookup_address(ctx, host); |
2166 | +} |
2167 | + |
2168 | +static void pri_parse_proxy(struct pri_context *ctx) |
2169 | +{ |
2170 | + char *proxy, *scheme, *host, *port, *path; |
2171 | + |
2172 | + g_free(ctx->proxy_host); |
2173 | + ctx->proxy_host = NULL; |
2174 | + |
2175 | + if (ctx->message_proxy[0] != '\0') |
2176 | + proxy = ctx->message_proxy; |
2177 | + else if (ctx->message_center[0] != '\0') |
2178 | + proxy = ctx->message_center; |
2179 | + else |
2180 | + return; |
2181 | |
2182 | scheme = g_strdup(proxy); |
2183 | if (scheme == NULL) |
2184 | @@ -577,8 +757,7 @@ |
2185 | } |
2186 | } |
2187 | |
2188 | - g_free(ctx->proxy_host); |
2189 | - ctx->proxy_host = g_strdup(host); |
2190 | + get_proxy_ip(ctx, host); |
2191 | |
2192 | g_free(scheme); |
2193 | } |
2194 | @@ -662,44 +841,6 @@ |
2195 | close(sk); |
2196 | } |
2197 | |
2198 | -static void pri_setproxy(const char *interface, const char *proxy) |
2199 | -{ |
2200 | - struct rtentry rt; |
2201 | - struct sockaddr_in addr; |
2202 | - int sk; |
2203 | - |
2204 | - if (interface == NULL) |
2205 | - return; |
2206 | - |
2207 | - sk = socket(PF_INET, SOCK_DGRAM, 0); |
2208 | - if (sk < 0) |
2209 | - return; |
2210 | - |
2211 | - memset(&rt, 0, sizeof(rt)); |
2212 | - rt.rt_flags = RTF_UP | RTF_HOST; |
2213 | - rt.rt_dev = (char *) interface; |
2214 | - |
2215 | - memset(&addr, 0, sizeof(addr)); |
2216 | - addr.sin_family = AF_INET; |
2217 | - addr.sin_addr.s_addr = inet_addr(proxy); |
2218 | - memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst)); |
2219 | - |
2220 | - memset(&addr, 0, sizeof(addr)); |
2221 | - addr.sin_family = AF_INET; |
2222 | - addr.sin_addr.s_addr = INADDR_ANY; |
2223 | - memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway)); |
2224 | - |
2225 | - memset(&addr, 0, sizeof(addr)); |
2226 | - addr.sin_family = AF_INET; |
2227 | - addr.sin_addr.s_addr = INADDR_ANY; |
2228 | - memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask)); |
2229 | - |
2230 | - if (ioctl(sk, SIOCADDRT, &rt) < 0) |
2231 | - ofono_error("Failed to add proxy host route"); |
2232 | - |
2233 | - close(sk); |
2234 | -} |
2235 | - |
2236 | static void pri_reset_context_settings(struct pri_context *ctx) |
2237 | { |
2238 | struct context_settings *settings; |
2239 | @@ -736,24 +877,6 @@ |
2240 | g_free(interface); |
2241 | } |
2242 | |
2243 | -static void pri_update_mms_context_settings(struct pri_context *ctx) |
2244 | -{ |
2245 | - struct ofono_gprs_context *gc = ctx->context_driver; |
2246 | - struct context_settings *settings = gc->settings; |
2247 | - |
2248 | - if (ctx->message_proxy) |
2249 | - settings->ipv4->proxy = g_strdup(ctx->message_proxy); |
2250 | - |
2251 | - pri_parse_proxy(ctx, ctx->message_proxy); |
2252 | - |
2253 | - DBG("proxy %s port %u", ctx->proxy_host, ctx->proxy_port); |
2254 | - |
2255 | - pri_set_ipv4_addr(settings->interface, settings->ipv4->ip); |
2256 | - |
2257 | - if (ctx->proxy_host) |
2258 | - pri_setproxy(settings->interface, ctx->proxy_host); |
2259 | -} |
2260 | - |
2261 | static void append_context_properties(struct pri_context *ctx, |
2262 | DBusMessageIter *dict) |
2263 | { |
2264 | @@ -835,8 +958,6 @@ |
2265 | { |
2266 | struct pri_context *ctx = data; |
2267 | struct ofono_gprs_context *gc = ctx->context_driver; |
2268 | - DBusConnection *conn = ofono_dbus_get_connection(); |
2269 | - dbus_bool_t value; |
2270 | |
2271 | DBG("%p", ctx); |
2272 | |
2273 | @@ -850,25 +971,23 @@ |
2274 | return; |
2275 | } |
2276 | |
2277 | - ctx->active = TRUE; |
2278 | - __ofono_dbus_pending_reply(&ctx->pending, |
2279 | - dbus_message_new_method_return(ctx->pending)); |
2280 | - |
2281 | if (gc->settings->interface != NULL) { |
2282 | pri_ifupdown(gc->settings->interface, TRUE); |
2283 | |
2284 | - if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_MMS && |
2285 | - gc->settings->ipv4) |
2286 | - pri_update_mms_context_settings(ctx); |
2287 | - |
2288 | - pri_context_signal_settings(ctx, gc->settings->ipv4 != NULL, |
2289 | - gc->settings->ipv6 != NULL); |
2290 | + if (gc->settings->ipv4) { |
2291 | + if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_MMS) |
2292 | + pri_set_ipv4_addr(gc->settings->interface, |
2293 | + gc->settings->ipv4->ip); |
2294 | + |
2295 | + pri_parse_proxy(ctx); |
2296 | + |
2297 | + /* Not answer yet if waiting for DNS lookup */ |
2298 | + if (ctx->lookup_req != NULL) |
2299 | + return; |
2300 | + } |
2301 | } |
2302 | |
2303 | - value = ctx->active; |
2304 | - ofono_dbus_signal_property_changed(conn, ctx->path, |
2305 | - OFONO_CONNECTION_CONTEXT_INTERFACE, |
2306 | - "Active", DBUS_TYPE_BOOLEAN, &value); |
2307 | + pri_activate_finish(ctx); |
2308 | } |
2309 | |
2310 | static void pri_deactivate_callback(const struct ofono_error *error, void *data) |
2311 | @@ -897,15 +1016,11 @@ |
2312 | "Active", DBUS_TYPE_BOOLEAN, &value); |
2313 | } |
2314 | |
2315 | -static DBusMessage *pri_set_preferred(struct pri_context *ctx, |
2316 | - DBusConnection *conn, |
2317 | - DBusMessage *msg, gboolean preferred) |
2318 | +static void set_preferred(struct pri_context *ctx, DBusConnection *conn, |
2319 | + gboolean preferred) |
2320 | { |
2321 | GKeyFile *settings = ctx->gprs->settings; |
2322 | |
2323 | - if (ctx->preferred == preferred) |
2324 | - return dbus_message_new_method_return(msg); |
2325 | - |
2326 | ctx->preferred = preferred; |
2327 | |
2328 | if (settings) { |
2329 | @@ -914,12 +1029,22 @@ |
2330 | storage_sync(ctx->gprs->imsi, SETTINGS_STORE, settings); |
2331 | } |
2332 | |
2333 | - g_dbus_send_reply(conn, msg, DBUS_TYPE_INVALID); |
2334 | - |
2335 | ofono_dbus_signal_property_changed(conn, ctx->path, |
2336 | OFONO_CONNECTION_CONTEXT_INTERFACE, |
2337 | "Preferred", DBUS_TYPE_BOOLEAN, |
2338 | &preferred); |
2339 | +} |
2340 | + |
2341 | +static DBusMessage *pri_set_preferred(struct pri_context *ctx, |
2342 | + DBusConnection *conn, |
2343 | + DBusMessage *msg, gboolean preferred) |
2344 | +{ |
2345 | + if (ctx->preferred == preferred) |
2346 | + return dbus_message_new_method_return(msg); |
2347 | + |
2348 | + g_dbus_send_reply(conn, msg, DBUS_TYPE_INVALID); |
2349 | + |
2350 | + set_preferred(ctx, conn, preferred); |
2351 | |
2352 | return NULL; |
2353 | } |
2354 | @@ -3186,20 +3311,48 @@ |
2355 | static struct pri_context *gprs_context_for_ia(struct ofono_gprs *gprs) |
2356 | { |
2357 | GSList *l; |
2358 | - |
2359 | - for (l = gprs->contexts; l; l = l->next) { |
2360 | - struct pri_context *ctx = l->data; |
2361 | - |
2362 | - if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_IA) |
2363 | - return ctx; |
2364 | - } |
2365 | - |
2366 | - for (l = gprs->contexts; l; l = l->next) { |
2367 | - struct pri_context *ctx = l->data; |
2368 | - |
2369 | - if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_INTERNET) |
2370 | - return ctx; |
2371 | - } |
2372 | + struct pri_context *ctx_ia = NULL; |
2373 | + struct pri_context *ctx_inet_pref = NULL; |
2374 | + struct pri_context *ctx_inet = NULL; |
2375 | + struct pri_context *ctx_other_pref = NULL; |
2376 | + |
2377 | + for (l = gprs->contexts; l; l = l->next) { |
2378 | + struct pri_context *ctx = l->data; |
2379 | + |
2380 | + if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_IA) { |
2381 | + if (ctx->preferred) |
2382 | + return ctx; |
2383 | + |
2384 | + if (ctx_ia == NULL) |
2385 | + ctx_ia = ctx; |
2386 | + } else if (ctx->type == OFONO_GPRS_CONTEXT_TYPE_INTERNET) { |
2387 | + |
2388 | + if (ctx->preferred && ctx_inet_pref == NULL) |
2389 | + ctx_inet_pref = ctx; |
2390 | + else if (ctx_inet == NULL) |
2391 | + ctx_inet = ctx; |
2392 | + |
2393 | + } else if (ctx->preferred && ctx_other_pref == NULL) { |
2394 | + ctx_other_pref = ctx; |
2395 | + } |
2396 | + } |
2397 | + |
2398 | + if (ctx_ia != NULL) { |
2399 | + set_preferred(ctx_ia, ofono_dbus_get_connection(), TRUE); |
2400 | + return ctx_ia; |
2401 | + } |
2402 | + |
2403 | + if (ctx_inet_pref != NULL) |
2404 | + return ctx_inet_pref; |
2405 | + |
2406 | + if (ctx_inet != NULL) |
2407 | + return ctx_inet; |
2408 | + |
2409 | + if (ctx_other_pref != NULL) |
2410 | + return ctx_other_pref; |
2411 | + |
2412 | + if (gprs->contexts == NULL) |
2413 | + return NULL; |
2414 | |
2415 | return gprs->contexts->data; |
2416 | } |
2417 | @@ -3213,11 +3366,16 @@ |
2418 | static void set_ia_apn(struct ofono_gprs *gprs) |
2419 | { |
2420 | struct pri_context *ctx = gprs_context_for_ia(gprs); |
2421 | - struct ofono_gprs_primary_context *ofono_ctx = &ctx->context; |
2422 | + struct ofono_gprs_primary_context *ofono_ctx; |
2423 | char mccmnc[OFONO_MAX_MCC_LENGTH + OFONO_MAX_MNC_LENGTH + 1]; |
2424 | const char *mcc = ofono_sim_get_mcc(gprs->sim); |
2425 | const char *mnc = ofono_sim_get_mnc(gprs->sim); |
2426 | |
2427 | + if (ctx == NULL) |
2428 | + return; |
2429 | + |
2430 | + ofono_ctx = &ctx->context; |
2431 | + |
2432 | strcpy(mccmnc, mcc); |
2433 | strcpy(mccmnc + strlen(mcc), mnc); |
2434 | |
2435 | |
2436 | === modified file 'src/radio-settings.c' |
2437 | --- src/radio-settings.c 2014-07-24 08:31:18 +0000 |
2438 | +++ src/radio-settings.c 2015-07-02 17:01:42 +0000 |
2439 | @@ -338,7 +338,7 @@ |
2440 | radio_set_band(rs); |
2441 | } |
2442 | |
2443 | -static void radio_set_rat_mode(struct ofono_radio_settings *rs, |
2444 | +void ofono_radio_settings_set_rat_mode(struct ofono_radio_settings *rs, |
2445 | enum ofono_radio_access_mode mode) |
2446 | { |
2447 | DBusConnection *conn = ofono_dbus_get_connection(); |
2448 | @@ -378,7 +378,7 @@ |
2449 | reply = dbus_message_new_method_return(rs->pending); |
2450 | __ofono_dbus_pending_reply(&rs->pending, reply); |
2451 | |
2452 | - radio_set_rat_mode(rs, rs->pending_mode); |
2453 | + ofono_radio_settings_set_rat_mode(rs, rs->pending_mode); |
2454 | } |
2455 | |
2456 | static void radio_send_properties_reply(struct ofono_radio_settings *rs) |
2457 | @@ -513,7 +513,7 @@ |
2458 | return; |
2459 | } |
2460 | |
2461 | - radio_set_rat_mode(rs, mode); |
2462 | + ofono_radio_settings_set_rat_mode(rs, mode); |
2463 | radio_query_band(rs); |
2464 | } |
2465 | |
2466 | |
2467 | === modified file 'test/list-contexts' |
2468 | --- test/list-contexts 2014-02-26 09:12:18 +0000 |
2469 | +++ test/list-contexts 2015-07-02 17:01:42 +0000 |
2470 | @@ -31,7 +31,7 @@ |
2471 | if i in ["DomainNameServers"]: |
2472 | for n in properties[key][i]: |
2473 | val += n + "," |
2474 | - elif i in ["PrefixLength"]: |
2475 | + elif i in ["PrefixLength", "ProxyPort"]: |
2476 | p = int(properties[key][i]) |
2477 | val += str(p) |
2478 | else: |
2479 | |
2480 | === modified file 'test/list-modems' |
2481 | --- test/list-modems 2015-05-20 16:32:09 +0000 |
2482 | +++ test/list-modems 2015-07-02 17:01:42 +0000 |
2483 | @@ -13,10 +13,11 @@ |
2484 | parser.add_argument("-p", |
2485 | "--private", |
2486 | dest="priv", |
2487 | - help="""Specifies that properties considered private |
2488 | - should be output as clear-text vs. obfuscated""", |
2489 | - action="store_false", |
2490 | - default="true" |
2491 | + help="""Specifies that properties considered |
2492 | + private should be output obfuscated vs. |
2493 | + cleartext (default).""", |
2494 | + action="store_true", |
2495 | + default=False |
2496 | ) |
2497 | |
2498 | return parser.parse_args() |
2499 | |
2500 | === modified file 'test/rilmodem/sim/simtestutil.py' |
2501 | --- test/rilmodem/sim/simtestutil.py 2014-12-15 19:11:43 +0000 |
2502 | +++ test/rilmodem/sim/simtestutil.py 2015-07-02 17:01:42 +0000 |
2503 | @@ -176,7 +176,7 @@ |
2504 | path), |
2505 | 'org.ofono.SimManager') |
2506 | def if_supports_sim_offline(self): |
2507 | - if self.product != "krillin": |
2508 | + if self.product != "krillin" and self.product != "arale": |
2509 | return True |
2510 | else: |
2511 | return False |
2512 | @@ -225,7 +225,7 @@ |
2513 | else: |
2514 | check_features = no_sim_online_features[:] |
2515 | else: |
2516 | - if self.product == "krillin": |
2517 | + if self.product == "krillin" or self.product == "arale": |
2518 | check_features = [] |
2519 | else: |
2520 | if test_sims: |
2521 | @@ -264,7 +264,7 @@ |
2522 | else: |
2523 | |
2524 | # krillin no diff between sim/no-SIM when offline |
2525 | - if self.product == "krillin": |
2526 | + if self.product == "krillin" or self.product == "arale": |
2527 | check_ifaces = no_sim_offline_ifaces[:] |
2528 | check_ifaces.append("org.ofono.NetworkTime") |
2529 | else: |
2530 | @@ -298,7 +298,7 @@ |
2531 | # |
2532 | # https://bugs.launchpad.net/ubuntu/+source/ofono/+bug/1396317 |
2533 | |
2534 | - if self.product == "krillin": |
2535 | + if self.product == "krillin" or self.product == "arale": |
2536 | self.assertTrue(properties["Muted"] == 0) |
2537 | else: |
2538 | self.assertTrue(properties["Muted"] == 1) |
2539 | |
2540 | === modified file 'test/rilmodem/sim/test-no-sims-offline' |
2541 | --- test/rilmodem/sim/test-no-sims-offline 2014-12-15 19:11:43 +0000 |
2542 | +++ test/rilmodem/sim/test-no-sims-offline 2015-07-02 17:01:42 +0000 |
2543 | @@ -67,7 +67,7 @@ |
2544 | self.validate_modem_properties(path, False, False) |
2545 | |
2546 | # krillin doesn't expose SimManager when offline |
2547 | - if (self.product != "krillin"): |
2548 | + if (self.product != "krillin" and self.product != "arale"): |
2549 | self.assertTrue(self.check_no_sim_present(path)) |
2550 | |
2551 | self.validate_emergency_numbers(path) |
2552 | |
2553 | === modified file 'test/rilmodem/sim/test-sims-offline' |
2554 | --- test/rilmodem/sim/test-sims-offline 2014-12-12 15:51:15 +0000 |
2555 | +++ test/rilmodem/sim/test-sims-offline 2015-07-02 17:01:42 +0000 |
2556 | @@ -89,7 +89,7 @@ |
2557 | self.validate_modem_properties(path, False, True) |
2558 | |
2559 | # krillin: no SIM access when modem offline |
2560 | - if (self.product != "krillin"): |
2561 | + if (self.product != "krillin" and self.product != "arale"): |
2562 | self.validate_sim_properties(path, self.args.mcc, |
2563 | self.args.mnc, |
2564 | self.args.subscriber) |
The code all looks good. That said, the changelog needs some fixing ( see inline comments ).