3 * oFono - Open Source Telephony
5 * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
6 * Copyright (C) 2010 ST-Ericsson AB.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 #include <ofono/log.h>
35 #include <ofono/modem.h>
36 #include <ofono/netreg.h>
39 #include "gatresult.h"
45 static const char *none_prefix[] = { NULL };
46 static const char *creg_prefix[] = { "+CREG:", NULL };
47 static const char *cops_prefix[] = { "+COPS:", NULL };
48 static const char *csq_prefix[] = { "+CSQ:", NULL };
49 static const char *cind_prefix[] = { "+CIND:", NULL };
50 static const char *cmer_prefix[] = { "+CMER:", NULL };
51 static const char *zpas_prefix[] = { "+ZPAS:", NULL };
52 static const char *option_tech_prefix[] = { "_OCTI:", "_OUWCTI:", NULL };
56 char mcc[OFONO_MAX_MCC_LENGTH + 1];
57 char mnc[OFONO_MAX_MNC_LENGTH + 1];
58 int signal_index; /* If strength is reported via CIND */
59 int signal_min; /* min strength reported via CIND */
60 int signal_max; /* max strength reported via CIND */
61 int signal_invalid; /* invalid strength reported via CIND */
63 struct ofono_network_time time;
72 struct ofono_netreg *netreg;
75 static void extract_mcc_mnc(const char *str, char *mcc, char *mnc)
77 /* Three digit country code */
78 strncpy(mcc, str, OFONO_MAX_MCC_LENGTH);
79 mcc[OFONO_MAX_MCC_LENGTH] = '\0';
81 /* Usually a 2 but sometimes 3 digit network code */
82 strncpy(mnc, str + OFONO_MAX_MCC_LENGTH, OFONO_MAX_MNC_LENGTH);
83 mnc[OFONO_MAX_MNC_LENGTH] = '\0';
86 static int zte_parse_tech(GAtResult *result)
89 const char *network, *domain;
92 g_at_result_iter_init(&iter, result);
94 if (!g_at_result_iter_next(&iter, "+ZPAS:"))
97 if (!g_at_result_iter_next_string(&iter, &network))
100 if (!g_at_result_iter_next_string(&iter, &domain))
103 if (g_str_equal(network, "GSM") == TRUE ||
104 g_str_equal(network, "GPRS") == TRUE)
105 tech = ACCESS_TECHNOLOGY_GSM;
106 else if (g_str_equal(network, "EDGE") == TRUE)
107 tech = ACCESS_TECHNOLOGY_GSM_EGPRS;
108 else if (g_str_equal(network, "UMTS") == TRUE)
109 tech = ACCESS_TECHNOLOGY_UTRAN;
110 else if (g_str_equal(network, "HSDPA") == TRUE)
111 tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA;
115 DBG("network %s domain %s tech %d", network, domain, tech);
120 static int option_parse_tech(GAtResult *result)
126 g_at_result_iter_init(&iter, result);
128 if (!g_at_result_iter_next(&iter, "_OCTI:"))
131 if (!g_at_result_iter_next_number(&iter, &s))
134 if (!g_at_result_iter_next_number(&iter, &octi))
137 if (!g_at_result_iter_next(&iter, "_OUWCTI:"))
140 if (!g_at_result_iter_next_number(&iter, &s))
143 if (!g_at_result_iter_next_number(&iter, &ouwcti))
148 tech = ACCESS_TECHNOLOGY_GSM;
151 tech = ACCESS_TECHNOLOGY_GSM;
154 tech = ACCESS_TECHNOLOGY_GSM_EGPRS;
163 tech = ACCESS_TECHNOLOGY_UTRAN;
166 tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA;
169 tech = ACCESS_TECHNOLOGY_UTRAN_HSUPA;
172 tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA;
176 DBG("octi %d ouwcti %d tech %d", octi, ouwcti, tech);
181 static void at_creg_cb(gboolean ok, GAtResult *result, gpointer user_data)
183 struct cb_data *cbd = user_data;
184 ofono_netreg_status_cb_t cb = cbd->cb;
185 int status, lac, ci, tech;
186 struct ofono_error error;
187 struct netreg_data *nd = cbd->user;
189 decode_at_error(&error, g_at_result_final_response(result));
192 cb(&error, -1, -1, -1, -1, cbd->data);
196 if (at_util_parse_reg(result, "+CREG:", NULL, &status,
197 &lac, &ci, &tech, nd->vendor) == FALSE) {
198 CALLBACK_WITH_FAILURE(cb, -1, -1, -1, -1, cbd->data);
202 if ((status == 1 || status == 5) && (tech == -1))
205 cb(&error, status, lac, ci, tech, cbd->data);
208 static void zte_tech_cb(gboolean ok, GAtResult *result, gpointer user_data)
210 struct cb_data *cbd = user_data;
211 struct ofono_netreg *netreg = cbd->data;
212 struct netreg_data *nd = ofono_netreg_get_data(netreg);
215 nd->tech = zte_parse_tech(result);
220 static void option_tech_cb(gboolean ok, GAtResult *result, gpointer user_data)
222 struct cb_data *cbd = user_data;
223 struct ofono_netreg *netreg = cbd->data;
224 struct netreg_data *nd = ofono_netreg_get_data(netreg);
227 nd->tech = option_parse_tech(result);
232 static void at_registration_status(struct ofono_netreg *netreg,
233 ofono_netreg_status_cb_t cb,
236 struct netreg_data *nd = ofono_netreg_get_data(netreg);
237 struct cb_data *cbd = cb_data_new(cb, data);
241 switch (nd->vendor) {
242 case OFONO_VENDOR_MBM:
244 * Send *ERINFO to find out the current tech, it will be
245 * intercepted in mbm_erinfo_notify
247 g_at_chat_send(nd->chat, "AT*ERINFO?", none_prefix,
250 case OFONO_VENDOR_GOBI:
252 * Send *CNTI=0 to find out the current tech, it will be
253 * intercepted in gobi_cnti_notify
255 g_at_chat_send(nd->chat, "AT*CNTI=0", none_prefix,
258 case OFONO_VENDOR_NOVATEL:
260 * Send $CNTI=0 to find out the current tech, it will be
261 * intercepted in nw_cnti_notify
263 g_at_chat_send(nd->chat, "AT$CNTI=0", none_prefix,
266 case OFONO_VENDOR_ZTE:
268 * Send +ZPAS? to find out the current tech, zte_tech_cb
269 * will call, fire CREG? to do the rest.
271 if (g_at_chat_send(nd->chat, "AT+ZPAS?", zpas_prefix,
272 zte_tech_cb, cbd, NULL) == 0)
275 case OFONO_VENDOR_OPTION_HSO:
277 * Send AT_OCTI?;_OUWCTI? to find out the current tech,
278 * option_tech_cb will call, fire CREG? to do the rest.
280 if (g_at_chat_send(nd->chat, "AT_OCTI?;_OUWCTI?",
282 option_tech_cb, cbd, NULL) == 0)
287 if (g_at_chat_send(nd->chat, "AT+CREG?", creg_prefix,
288 at_creg_cb, cbd, g_free) > 0)
293 CALLBACK_WITH_FAILURE(cb, -1, -1, -1, -1, data);
296 static void cops_cb(gboolean ok, GAtResult *result, gpointer user_data)
298 struct cb_data *cbd = user_data;
299 struct netreg_data *nd = ofono_netreg_get_data(cbd->user);
300 ofono_netreg_operator_cb_t cb = cbd->cb;
301 struct ofono_network_operator op;
305 struct ofono_error error;
307 decode_at_error(&error, g_at_result_final_response(result));
312 g_at_result_iter_init(&iter, result);
314 if (!g_at_result_iter_next(&iter, "+COPS:"))
317 g_at_result_iter_skip_next(&iter);
319 ok = g_at_result_iter_next_number(&iter, &format);
321 if (ok == FALSE || format != 0)
324 if (g_at_result_iter_next_string(&iter, &name) == FALSE)
328 if (g_at_result_iter_next_number(&iter, &tech) == FALSE)
329 tech = ACCESS_TECHNOLOGY_GSM;
331 strncpy(op.name, name, OFONO_MAX_OPERATOR_NAME_LENGTH);
332 op.name[OFONO_MAX_OPERATOR_NAME_LENGTH] = '\0';
334 strncpy(op.mcc, nd->mcc, OFONO_MAX_MCC_LENGTH);
335 op.mcc[OFONO_MAX_MCC_LENGTH] = '\0';
337 strncpy(op.mnc, nd->mnc, OFONO_MAX_MNC_LENGTH);
338 op.mnc[OFONO_MAX_MNC_LENGTH] = '\0';
344 DBG("cops_cb: %s, %s %s %d", name, nd->mcc, nd->mnc, tech);
346 cb(&error, &op, cbd->data);
352 cb(&error, NULL, cbd->data);
357 static void cops_numeric_cb(gboolean ok, GAtResult *result, gpointer user_data)
359 struct cb_data *cbd = user_data;
360 struct netreg_data *nd = ofono_netreg_get_data(cbd->user);
361 ofono_netreg_operator_cb_t cb = cbd->cb;
366 struct ofono_error error;
368 decode_at_error(&error, g_at_result_final_response(result));
373 g_at_result_iter_init(&iter, result);
375 if (!g_at_result_iter_next(&iter, "+COPS:"))
378 g_at_result_iter_skip_next(&iter);
380 ok = g_at_result_iter_next_number(&iter, &format);
382 if (ok == FALSE || format != 2)
385 if (g_at_result_iter_next_string(&iter, &str) == FALSE)
388 len = strspn(str, "0123456789");
390 if (len != 5 && len != 6)
393 extract_mcc_mnc(str, nd->mcc, nd->mnc);
395 DBG("Cops numeric got mcc: %s, mnc: %s", nd->mcc, nd->mnc);
397 ok = g_at_chat_send(nd->chat, "AT+COPS=3,0", none_prefix,
401 ok = g_at_chat_send(nd->chat, "AT+COPS?", cops_prefix,
408 cb(&error, NULL, cbd->data);
412 static void at_current_operator(struct ofono_netreg *netreg,
413 ofono_netreg_operator_cb_t cb, void *data)
415 struct netreg_data *nd = ofono_netreg_get_data(netreg);
416 struct cb_data *cbd = cb_data_new(cb, data);
421 /* Nokia modems have a broken return value for the string
422 * returned for the numeric value. It misses a " at the end.
423 * Trying to read this will stall the parser. So skip it. */
424 if (nd->vendor == OFONO_VENDOR_NOKIA) {
425 ok = g_at_chat_send(nd->chat, "AT+COPS=3,0", none_prefix,
429 ok = g_at_chat_send(nd->chat, "AT+COPS?", cops_prefix,
432 ok = g_at_chat_send(nd->chat, "AT+COPS=3,2", none_prefix,
436 ok = g_at_chat_send(nd->chat, "AT+COPS?", cops_prefix,
437 cops_numeric_cb, cbd, NULL);
445 CALLBACK_WITH_FAILURE(cb, NULL, data);
448 static void cops_list_cb(gboolean ok, GAtResult *result, gpointer user_data)
450 struct cb_data *cbd = user_data;
451 ofono_netreg_operator_list_cb_t cb = cbd->cb;
452 struct ofono_network_operator *list;
455 struct ofono_error error;
457 decode_at_error(&error, g_at_result_final_response(result));
460 cb(&error, 0, NULL, cbd->data);
464 g_at_result_iter_init(&iter, result);
466 while (g_at_result_iter_next(&iter, "+COPS:")) {
467 while (g_at_result_iter_skip_next(&iter))
471 DBG("Got %d elements", num);
473 list = g_try_new0(struct ofono_network_operator, num);
475 CALLBACK_WITH_FAILURE(cb, 0, NULL, cbd->data);
480 g_at_result_iter_init(&iter, result);
482 while (g_at_result_iter_next(&iter, "+COPS:")) {
483 int status, tech, plmn;
484 const char *l, *s, *n;
485 gboolean have_long = FALSE;
488 if (!g_at_result_iter_open_list(&iter))
491 if (!g_at_result_iter_next_number(&iter, &status))
494 list[num].status = status;
496 if (!g_at_result_iter_next_string(&iter, &l))
501 strncpy(list[num].name, l,
502 OFONO_MAX_OPERATOR_NAME_LENGTH);
505 if (!g_at_result_iter_next_string(&iter, &s))
508 if (strlen(s) > 0 && !have_long)
509 strncpy(list[num].name, s,
510 OFONO_MAX_OPERATOR_NAME_LENGTH);
512 list[num].name[OFONO_MAX_OPERATOR_NAME_LENGTH] = '\0';
514 if (!g_at_result_iter_next_string(&iter, &n))
517 extract_mcc_mnc(n, list[num].mcc, list[num].mnc);
519 if (!g_at_result_iter_next_number(&iter, &tech))
520 tech = ACCESS_TECHNOLOGY_GSM;
522 list[num].tech = tech;
524 if (!g_at_result_iter_next_number(&iter, &plmn))
527 if (!g_at_result_iter_close_list(&iter))
534 DBG("Got %d operators", num);
539 for (; i < num; i++) {
540 DBG("Operator: %s, %s, %s, status: %d, %d",
541 list[i].name, list[i].mcc, list[i].mnc,
542 list[i].status, list[i].tech);
546 cb(&error, num, list, cbd->data);
551 static void at_list_operators(struct ofono_netreg *netreg,
552 ofono_netreg_operator_list_cb_t cb, void *data)
554 struct netreg_data *nd = ofono_netreg_get_data(netreg);
555 struct cb_data *cbd = cb_data_new(cb, data);
557 if (g_at_chat_send(nd->chat, "AT+COPS=?", cops_prefix,
558 cops_list_cb, cbd, g_free) > 0)
563 CALLBACK_WITH_FAILURE(cb, 0, NULL, data);
566 static void register_cb(gboolean ok, GAtResult *result, gpointer user_data)
568 struct cb_data *cbd = user_data;
569 ofono_netreg_register_cb_t cb = cbd->cb;
570 struct ofono_error error;
572 decode_at_error(&error, g_at_result_final_response(result));
574 cb(&error, cbd->data);
577 static void at_register_auto(struct ofono_netreg *netreg,
578 ofono_netreg_register_cb_t cb, void *data)
580 struct netreg_data *nd = ofono_netreg_get_data(netreg);
581 struct cb_data *cbd = cb_data_new(cb, data);
583 if (g_at_chat_send(nd->chat, "AT+COPS=0", none_prefix,
584 register_cb, cbd, g_free) > 0)
589 CALLBACK_WITH_FAILURE(cb, data);
592 static void at_register_manual(struct ofono_netreg *netreg,
593 const char *mcc, const char *mnc,
594 ofono_netreg_register_cb_t cb, void *data)
596 struct netreg_data *nd = ofono_netreg_get_data(netreg);
597 struct cb_data *cbd = cb_data_new(cb, data);
600 snprintf(buf, sizeof(buf), "AT+COPS=1,2,\"%s%s\"", mcc, mnc);
602 if (g_at_chat_send(nd->chat, buf, none_prefix,
603 register_cb, cbd, g_free) > 0)
608 CALLBACK_WITH_FAILURE(cb, data);
611 static void csq_notify(GAtResult *result, gpointer user_data)
613 struct ofono_netreg *netreg = user_data;
617 g_at_result_iter_init(&iter, result);
619 if (!g_at_result_iter_next(&iter, "+CSQ:"))
622 if (!g_at_result_iter_next_number(&iter, &strength))
625 ofono_netreg_strength_notify(netreg,
626 at_util_convert_signal_strength(strength));
629 static void calypso_csq_notify(GAtResult *result, gpointer user_data)
631 struct ofono_netreg *netreg = user_data;
635 g_at_result_iter_init(&iter, result);
637 if (!g_at_result_iter_next(&iter, "%CSQ:"))
640 if (!g_at_result_iter_next_number(&iter, &strength))
643 ofono_netreg_strength_notify(netreg,
644 at_util_convert_signal_strength(strength));
647 static void option_osigq_notify(GAtResult *result, gpointer user_data)
649 struct ofono_netreg *netreg = user_data;
653 g_at_result_iter_init(&iter, result);
655 if (!g_at_result_iter_next(&iter, "_OSIGQ:"))
658 if (!g_at_result_iter_next_number(&iter, &strength))
661 ofono_netreg_strength_notify(netreg,
662 at_util_convert_signal_strength(strength));
665 static void ifx_xhomezr_notify(GAtResult *result, gpointer user_data)
667 //struct ofono_netreg *netreg = user_data;
671 g_at_result_iter_init(&iter, result);
673 if (!g_at_result_iter_next(&iter, "+XHOMEZR:"))
676 if (!g_at_result_iter_next_string(&iter, &label))
679 ofono_info("Home zone: %s", label);
682 static void ifx_xciev_notify(GAtResult *result, gpointer user_data)
684 //struct ofono_netreg *netreg = user_data;
688 g_at_result_iter_init(&iter, result);
690 if (!g_at_result_iter_next(&iter, "+XCIEV:"))
693 if (!g_at_result_iter_next_number(&iter, &ind))
699 * Radio signal strength indicators are defined for 0-7,
700 * but this notification seems to return CSQ 0-31,99 values.
702 * Ignore this indication for now since it can not be trusted.
706 static void ifx_xcsq_notify(GAtResult *result, gpointer user_data)
708 struct ofono_netreg *netreg = user_data;
709 int rssi, ber, strength;
712 g_at_result_iter_init(&iter, result);
714 if (!g_at_result_iter_next(&iter, "+XCSQ:"))
717 if (!g_at_result_iter_next_number(&iter, &rssi))
720 if (!g_at_result_iter_next_number(&iter, &ber))
723 DBG("rssi %d ber %d", rssi, ber);
728 strength = (rssi * 100) / 31;
730 ofono_netreg_strength_notify(netreg, strength);
733 static void ciev_notify(GAtResult *result, gpointer user_data)
735 struct ofono_netreg *netreg = user_data;
736 struct netreg_data *nd = ofono_netreg_get_data(netreg);
740 g_at_result_iter_init(&iter, result);
742 if (!g_at_result_iter_next(&iter, "+CIEV:"))
745 if (!g_at_result_iter_next_number(&iter, &ind))
748 if (ind != nd->signal_index)
751 if (!g_at_result_iter_next_number(&iter, &strength))
754 if (strength == nd->signal_invalid)
757 strength = (strength * 100) / (nd->signal_max - nd->signal_min);
759 ofono_netreg_strength_notify(netreg, strength);
762 static void telit_ciev_notify(GAtResult *result, gpointer user_data)
764 struct ofono_netreg *netreg = user_data;
765 struct netreg_data *nd = ofono_netreg_get_data(netreg);
766 const char *signal_identifier = "rssi";
771 g_at_result_iter_init(&iter, result);
773 if (!g_at_result_iter_next(&iter, "+CIEV:"))
776 if (!g_at_result_iter_next_unquoted_string(&iter, &ind_str))
779 if (!g_str_equal(signal_identifier, ind_str))
782 if (!g_at_result_iter_next_number(&iter, &strength))
785 if (strength == nd->signal_invalid)
788 strength = (strength * 100) / (nd->signal_max - nd->signal_min);
790 ofono_netreg_strength_notify(netreg, strength);
793 static void ctzv_notify(GAtResult *result, gpointer user_data)
795 struct ofono_netreg *netreg = user_data;
796 struct netreg_data *nd = ofono_netreg_get_data(netreg);
800 g_at_result_iter_init(&iter, result);
802 if (!g_at_result_iter_next(&iter, "+CTZV:"))
805 if (!g_at_result_iter_next_unquoted_string(&iter, &tz))
810 nd->time.utcoff = atoi(tz) * 15 * 60;
812 ofono_netreg_time_notify(netreg, &nd->time);
815 static void tlts_notify(GAtResult *result, gpointer user_data)
817 struct ofono_netreg *netreg = user_data;
818 struct netreg_data *nd = ofono_netreg_get_data(netreg);
819 int year, mon, mday, hour, min, sec;
824 g_at_result_iter_init(&iter, result);
826 if (!g_at_result_iter_next(&iter, "*TLTS:"))
829 if (!g_at_result_iter_next_string(&iter, &time))
832 DBG("time %s", time);
834 if (sscanf(time, "%02u/%02u/%02u,%02u:%02u:%02u%s", &year, &mon, &mday,
835 &hour, &min, &sec, tz) != 7)
840 nd->time.hour = hour;
841 nd->time.mday = mday;
843 nd->time.year = 2000 + year;
845 nd->time.utcoff = atoi(tz) * 15 * 60;
847 ofono_netreg_time_notify(netreg, &nd->time);
850 static gboolean notify_time(gpointer user_data)
852 struct ofono_netreg *netreg = user_data;
853 struct netreg_data *nd = ofono_netreg_get_data(netreg);
855 nd->nitz_timeout = 0;
857 ofono_netreg_time_notify(netreg, &nd->time);
862 static void ifx_ctzv_notify(GAtResult *result, gpointer user_data)
864 struct ofono_netreg *netreg = user_data;
865 struct netreg_data *nd = ofono_netreg_get_data(netreg);
866 int year, mon, mday, hour, min, sec;
867 const char *tz, *time;
870 g_at_result_iter_init(&iter, result);
872 if (!g_at_result_iter_next(&iter, "+CTZV:"))
875 if (!g_at_result_iter_next_unquoted_string(&iter, &tz))
878 if (!g_at_result_iter_next_string(&iter, &time))
881 DBG("tz %s time %s", tz, time);
883 if (sscanf(time, "%u/%u/%u,%u:%u:%u", &year, &mon, &mday,
884 &hour, &min, &sec) != 6)
889 nd->time.hour = hour;
890 nd->time.mday = mday;
892 nd->time.year = 2000 + year;
894 if (nd->nitz_timeout > 0)
895 g_source_remove(nd->nitz_timeout);
897 nd->nitz_timeout = g_timeout_add_seconds(1, notify_time, user_data);
900 static void ifx_ctzdst_notify(GAtResult *result, gpointer user_data)
902 struct ofono_netreg *netreg = user_data;
903 struct netreg_data *nd = ofono_netreg_get_data(netreg);
907 g_at_result_iter_init(&iter, result);
909 if (!g_at_result_iter_next(&iter, "+CTZDST:"))
912 if (!g_at_result_iter_next_number(&iter, &dst))
919 if (nd->nitz_timeout > 0) {
920 g_source_remove(nd->nitz_timeout);
921 nd->nitz_timeout = 0;
924 ofono_netreg_time_notify(netreg, &nd->time);
927 static void cind_cb(gboolean ok, GAtResult *result, gpointer user_data)
929 struct cb_data *cbd = user_data;
930 ofono_netreg_strength_cb_t cb = cbd->cb;
931 struct netreg_data *nd = cbd->user;
935 struct ofono_error error;
937 decode_at_error(&error, g_at_result_final_response(result));
940 cb(&error, -1, cbd->data);
944 g_at_result_iter_init(&iter, result);
946 if (!g_at_result_iter_next(&iter, "+CIND:")) {
947 CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
951 for (index = 1; index < nd->signal_index; index++)
952 g_at_result_iter_skip_next(&iter);
954 g_at_result_iter_next_number(&iter, &strength);
956 if (strength == nd->signal_invalid)
959 strength = (strength * 100) / (nd->signal_max - nd->signal_min);
961 cb(&error, strength, cbd->data);
964 static void huawei_rssi_notify(GAtResult *result, gpointer user_data)
966 struct ofono_netreg *netreg = user_data;
970 g_at_result_iter_init(&iter, result);
972 if (!g_at_result_iter_next(&iter, "^RSSI:"))
975 if (!g_at_result_iter_next_number(&iter, &strength))
978 ofono_netreg_strength_notify(netreg,
979 at_util_convert_signal_strength(strength));
982 static void huawei_mode_notify(GAtResult *result, gpointer user_data)
984 struct ofono_netreg *netreg = user_data;
985 struct netreg_data *nd = ofono_netreg_get_data(netreg);
989 g_at_result_iter_init(&iter, result);
991 if (!g_at_result_iter_next(&iter, "^MODE:"))
994 if (!g_at_result_iter_next_number(&iter, &mode))
997 if (!g_at_result_iter_next_number(&iter, &submode))
1002 nd->tech = ACCESS_TECHNOLOGY_GSM;
1005 nd->tech = ACCESS_TECHNOLOGY_UTRAN;
1010 static void huawei_nwtime_notify(GAtResult *result, gpointer user_data)
1012 struct ofono_netreg *netreg = user_data;
1013 struct netreg_data *nd = ofono_netreg_get_data(netreg);
1014 int year, mon, mday, hour, min, sec;
1016 const char *date, *time, *dst;
1019 g_at_result_iter_init(&iter, result);
1021 if (!g_at_result_iter_next(&iter, "^NWTIME:"))
1024 if (!g_at_result_iter_next_unquoted_string(&iter, &date))
1027 if (!g_at_result_iter_next_unquoted_string(&iter, &time))
1030 if (!g_at_result_iter_next_unquoted_string(&iter, &dst))
1033 DBG("date %s time %s dst %s", date, time, dst);
1035 if (sscanf(date, "%u/%u/%u", &year, &mon, &mday) != 3)
1038 if (sscanf(time, "%u:%u:%u%s", &hour, &min, &sec, tz) != 4)
1041 nd->time.utcoff = atoi(tz) * 15 * 60;
1042 nd->time.dst = atoi(dst);
1046 nd->time.hour = hour;
1047 nd->time.mday = mday;
1049 nd->time.year = 2000 + year;
1051 ofono_netreg_time_notify(netreg, &nd->time);
1054 static void csq_cb(gboolean ok, GAtResult *result, gpointer user_data)
1056 struct cb_data *cbd = user_data;
1057 ofono_netreg_strength_cb_t cb = cbd->cb;
1060 struct ofono_error error;
1062 decode_at_error(&error, g_at_result_final_response(result));
1065 cb(&error, -1, cbd->data);
1069 g_at_result_iter_init(&iter, result);
1071 if (!g_at_result_iter_next(&iter, "+CSQ:")) {
1072 CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
1076 g_at_result_iter_next_number(&iter, &strength);
1078 DBG("csq_cb: %d", strength);
1083 strength = (strength * 100) / 31;
1085 cb(&error, strength, cbd->data);
1088 static void at_signal_strength(struct ofono_netreg *netreg,
1089 ofono_netreg_strength_cb_t cb, void *data)
1091 struct netreg_data *nd = ofono_netreg_get_data(netreg);
1092 struct cb_data *cbd = cb_data_new(cb, data);
1097 * If we defaulted to using CIND, then keep using it,
1098 * otherwise fall back to CSQ
1100 if (nd->signal_index > 0) {
1101 if (g_at_chat_send(nd->chat, "AT+CIND?", cind_prefix,
1102 cind_cb, cbd, g_free) > 0)
1105 if (g_at_chat_send(nd->chat, "AT+CSQ", csq_prefix,
1106 csq_cb, cbd, g_free) > 0)
1112 CALLBACK_WITH_FAILURE(cb, -1, data);
1115 static void mbm_etzv_notify(GAtResult *result, gpointer user_data)
1117 struct ofono_netreg *netreg = user_data;
1118 struct netreg_data *nd = ofono_netreg_get_data(netreg);
1119 int year, mon, mday, hour, min, sec;
1120 const char *tz, *time, *timestamp;
1123 g_at_result_iter_init(&iter, result);
1125 if (g_at_result_iter_next(&iter, "*ETZV:") == FALSE)
1128 if (g_at_result_iter_next_string(&iter, &tz) == FALSE)
1131 if (g_at_result_iter_next_string(&iter, &time) == FALSE)
1134 if (g_at_result_iter_next_string(&iter, ×tamp) == FALSE)
1137 DBG("tz %s time %s timestamp %s", tz, time, timestamp);
1147 if (sscanf(time, "%u/%u/%u,%u:%u:%u", &year, &mon, &mday,
1148 &hour, &min, &sec) != 6)
1152 nd->time.utcoff = atoi(tz) * 15 * 60;
1156 nd->time.hour = hour;
1157 nd->time.mday = mday;
1159 nd->time.year = year;
1161 ofono_netreg_time_notify(netreg, &nd->time);
1164 static void mbm_erinfo_notify(GAtResult *result, gpointer user_data)
1166 struct ofono_netreg *netreg = user_data;
1167 struct netreg_data *nd = ofono_netreg_get_data(netreg);
1169 int mode, gsm, umts;
1171 g_at_result_iter_init(&iter, result);
1173 if (g_at_result_iter_next(&iter, "*ERINFO:") == FALSE)
1176 if (g_at_result_iter_next_number(&iter, &mode) == FALSE)
1179 if (g_at_result_iter_next_number(&iter, &gsm) == FALSE)
1183 * According to MBM the ERINFO unsolicited response does not contain
1184 * the mode parameter, however at least the MD300 does report it. So
1185 * we handle both 2 and 3 argument versions
1187 if (g_at_result_iter_next_number(&iter, &umts) == FALSE) {
1192 ofono_info("network capability: GSM %d UMTS %d", gsm, umts);
1194 /* Convert to tech values from 27.007 */
1197 nd->tech = ACCESS_TECHNOLOGY_GSM;
1200 nd->tech = ACCESS_TECHNOLOGY_GSM_EGPRS;
1208 nd->tech = ACCESS_TECHNOLOGY_UTRAN;
1210 case 2: /* UMTS + HSDPA */
1211 nd->tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA;
1216 static void icera_nwstate_notify(GAtResult *result, gpointer user_data)
1218 struct ofono_netreg *netreg = user_data;
1219 struct netreg_data *nd = ofono_netreg_get_data(netreg);
1221 const char *mccmnc, *tech, *state;
1224 g_at_result_iter_init(&iter, result);
1226 if (g_at_result_iter_next(&iter, "%NWSTATE:") == FALSE)
1229 if (g_at_result_iter_next_number(&iter, &rssi) == FALSE)
1232 if (g_at_result_iter_next_unquoted_string(&iter, &mccmnc) == FALSE)
1235 if (g_at_result_iter_next_unquoted_string(&iter, &tech) == FALSE)
1238 if (g_at_result_iter_next_unquoted_string(&iter, &state) == FALSE)
1241 DBG("rssi %d tech %s state %s", rssi, tech, state);
1243 /* small 'g' means CS, big 'G' means PS */
1244 if (g_str_equal(tech, "2g") == TRUE ||
1245 g_str_equal(tech, "2G") == TRUE ||
1246 g_str_equal(tech, "2G-GPRS") == TRUE) {
1247 nd->tech = ACCESS_TECHNOLOGY_GSM;
1248 } else if (g_str_equal(tech, "2G-EDGE") == TRUE) {
1249 nd->tech = ACCESS_TECHNOLOGY_GSM_EGPRS;
1250 } else if (g_str_equal(tech, "3g") == TRUE ||
1251 g_str_equal(tech, "3G") == TRUE ||
1252 g_str_equal(tech, "R99") == TRUE) {
1253 if (g_str_equal(state, "HSDPA") == TRUE)
1254 nd->tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA;
1255 else if (g_str_equal(state, "HSUPA") == TRUE)
1256 nd->tech = ACCESS_TECHNOLOGY_UTRAN_HSUPA;
1257 else if (g_str_equal(state, "HSDPA-HSUPA") == TRUE)
1258 nd->tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA;
1259 else if (g_str_equal(state, "HSDPA-HSUPA-HSPA+") == TRUE)
1260 nd->tech = ACCESS_TECHNOLOGY_UTRAN_HSDPA_HSUPA;
1262 nd->tech = ACCESS_TECHNOLOGY_UTRAN;
1267 static int cnti_to_tech(const char *cnti)
1269 if (g_str_equal(cnti, "GSM") == TRUE ||
1270 g_str_equal(cnti, "GPRS") == TRUE)
1271 return ACCESS_TECHNOLOGY_GSM;
1272 else if (g_str_equal(cnti, "EDGE") == TRUE)
1273 return ACCESS_TECHNOLOGY_GSM_EGPRS;
1274 else if (g_str_equal(cnti, "UMTS") == TRUE)
1275 return ACCESS_TECHNOLOGY_UTRAN;
1276 else if (g_str_equal(cnti, "HSDPA") == TRUE)
1277 return ACCESS_TECHNOLOGY_UTRAN_HSDPA;
1278 else if (g_str_equal(cnti, "HSUPA") == TRUE)
1279 return ACCESS_TECHNOLOGY_UTRAN_HSUPA;
1284 static void gobi_cnti_notify(GAtResult *result, gpointer user_data)
1286 struct ofono_netreg *netreg = user_data;
1287 struct netreg_data *nd = ofono_netreg_get_data(netreg);
1292 g_at_result_iter_init(&iter, result);
1294 if (g_at_result_iter_next(&iter, "*CNTI:") == FALSE)
1297 if (g_at_result_iter_next_number(&iter, &option) == FALSE)
1303 if (g_at_result_iter_next_unquoted_string(&iter, &tech) == FALSE)
1306 nd->tech = cnti_to_tech(tech);
1309 static void nw_cnti_notify(GAtResult *result, gpointer user_data)
1311 struct ofono_netreg *netreg = user_data;
1312 struct netreg_data *nd = ofono_netreg_get_data(netreg);
1317 g_at_result_iter_init(&iter, result);
1319 if (g_at_result_iter_next(&iter, "$CNTI:") == FALSE)
1322 if (g_at_result_iter_next_number(&iter, &option) == FALSE)
1328 if (g_at_result_iter_next_unquoted_string(&iter, &tech) == FALSE)
1331 nd->tech = cnti_to_tech(tech);
1334 static void cnti_query_tech_cb(gboolean ok, GAtResult *result,
1337 struct tech_query *tq = user_data;
1338 struct netreg_data *nd = ofono_netreg_get_data(tq->netreg);
1340 ofono_netreg_status_notify(tq->netreg,
1341 tq->status, tq->lac, tq->ci, nd->tech);
1344 static void zte_query_tech_cb(gboolean ok, GAtResult *result,
1347 struct tech_query *tq = user_data;
1351 tech = zte_parse_tech(result);
1355 ofono_netreg_status_notify(tq->netreg,
1356 tq->status, tq->lac, tq->ci, tech);
1359 static void option_query_tech_cb(gboolean ok, GAtResult *result,
1362 struct tech_query *tq = user_data;
1366 tech = option_parse_tech(result);
1370 ofono_netreg_status_notify(tq->netreg,
1371 tq->status, tq->lac, tq->ci, tech);
1374 static void creg_notify(GAtResult *result, gpointer user_data)
1376 struct ofono_netreg *netreg = user_data;
1377 int status, lac, ci, tech;
1378 struct netreg_data *nd = ofono_netreg_get_data(netreg);
1379 struct tech_query *tq;
1381 if (at_util_parse_reg_unsolicited(result, "+CREG:", &status,
1382 &lac, &ci, &tech, nd->vendor) == FALSE)
1385 if (status != 1 && status != 5)
1388 tq = g_try_new0(struct tech_query, 1);
1392 tq->status = status;
1395 tq->netreg = netreg;
1397 switch (nd->vendor) {
1398 case OFONO_VENDOR_GOBI:
1399 if (g_at_chat_send(nd->chat, "AT*CNTI=0", none_prefix,
1400 cnti_query_tech_cb, tq, g_free) > 0)
1403 case OFONO_VENDOR_NOVATEL:
1404 if (g_at_chat_send(nd->chat, "AT$CNTI=0", none_prefix,
1405 cnti_query_tech_cb, tq, g_free) > 0)
1408 case OFONO_VENDOR_ZTE:
1409 if (g_at_chat_send(nd->chat, "AT+ZPAS?", zpas_prefix,
1410 zte_query_tech_cb, tq, g_free) > 0)
1413 case OFONO_VENDOR_OPTION_HSO:
1414 if (g_at_chat_send(nd->chat, "AT_OCTI?;_OUWCTI?",
1416 option_query_tech_cb, tq, g_free) > 0)
1423 if ((status == 1 || status == 5) && tech == -1)
1427 ofono_netreg_status_notify(netreg, status, lac, ci, tech);
1430 static void at_cmer_not_supported(struct ofono_netreg *netreg)
1432 ofono_error("+CMER not supported by this modem. If this is an error"
1433 " please submit patches to support this hardware");
1435 ofono_netreg_remove(netreg);
1438 static void at_cmer_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
1440 struct ofono_netreg *netreg = user_data;
1441 struct netreg_data *nd = ofono_netreg_get_data(netreg);
1444 at_cmer_not_supported(netreg);
1449 * Telit uses strings instead of numbers to identify indicators
1451 * Handle them in a separate function to keep the code clean.
1453 if (nd->vendor == OFONO_VENDOR_TELIT)
1454 g_at_chat_register(nd->chat, "+CIEV:",
1455 telit_ciev_notify, FALSE, netreg, NULL);
1457 g_at_chat_register(nd->chat, "+CIEV:",
1458 ciev_notify, FALSE, netreg, NULL);
1460 g_at_chat_register(nd->chat, "+CREG:",
1461 creg_notify, FALSE, netreg, NULL);
1463 ofono_netreg_register(netreg);
1466 static inline char wanted_cmer(int supported, const char *pref)
1469 if (supported & (1 << (*pref - '0')))
1478 static inline ofono_bool_t append_cmer_element(char *buf, int *len, int cap,
1482 char setting = wanted_cmer(cap, wanted);
1487 buf[*len] = setting;
1490 buf[*len + 1] = '\0';
1492 buf[*len + 1] = ',';
1499 static ofono_bool_t build_cmer_string(char *buf, int *cmer_opts,
1500 struct netreg_data *nd)
1503 int len = sprintf(buf, "AT+CMER=");
1508 * Forward unsolicited result codes directly to the TE;
1509 * TA‑TE link specific inband technique used to embed result codes and
1510 * data when TA is in on‑line data mode
1512 if (!append_cmer_element(buf, &len, cmer_opts[0], "3", FALSE))
1515 /* No keypad event reporting */
1516 if (!append_cmer_element(buf, &len, cmer_opts[1], "0", FALSE))
1519 /* No display event reporting */
1520 if (!append_cmer_element(buf, &len, cmer_opts[2], "0", FALSE))
1523 switch (nd->vendor) {
1524 case OFONO_VENDOR_TELIT:
1526 * Telit does not support mode 1.
1527 * All indicator events shall be directed from TA to TE.
1533 * Only those indicator events, which are not caused by +CIND
1534 * shall be indicated by the TA to the TE.
1541 * Indicator event reporting using URC +CIEV:Â <ind>,<value>.
1542 * <ind> indicates the indicator order number (as specified for +CIND)
1543 * and <value> is the new value of indicator.
1545 if (!append_cmer_element(buf, &len, cmer_opts[3], mode, TRUE))
1551 static void at_cmer_query_cb(ofono_bool_t ok, GAtResult *result,
1554 struct ofono_netreg *netreg = user_data;
1555 struct netreg_data *nd = ofono_netreg_get_data(netreg);
1557 int cmer_opts_cnt = 5; /* See 27.007 Section 8.10 */
1558 int cmer_opts[cmer_opts_cnt];
1566 memset(cmer_opts, 0, sizeof(cmer_opts));
1568 g_at_result_iter_init(&iter, result);
1570 if (!g_at_result_iter_next(&iter, "+CMER:"))
1573 for (opt = 0; opt < cmer_opts_cnt; opt++) {
1576 if (!g_at_result_iter_open_list(&iter))
1579 while (g_at_result_iter_next_range(&iter, &min, &max)) {
1580 for (mode = min; mode <= max; mode++)
1581 cmer_opts[opt] |= 1 << mode;
1584 if (!g_at_result_iter_close_list(&iter))
1588 if (build_cmer_string(buf, cmer_opts, nd) == FALSE)
1591 g_at_chat_send(nd->chat, buf, cmer_prefix,
1592 at_cmer_set_cb, netreg, NULL);
1597 at_cmer_not_supported(netreg);
1600 static void cind_support_cb(gboolean ok, GAtResult *result, gpointer user_data)
1602 struct ofono_netreg *netreg = user_data;
1603 struct netreg_data *nd = ofono_netreg_get_data(netreg);
1606 char *signal_identifier = "signal";
1610 int tmp_min, tmp_max, invalid;
1615 g_at_result_iter_init(&iter, result);
1616 if (!g_at_result_iter_next(&iter, "+CIND:"))
1622 * Telit encapsulates the CIND=? tokens with braces
1623 * so we need to skip them
1625 if (nd->vendor == OFONO_VENDOR_TELIT) {
1626 g_at_result_iter_open_list(&iter);
1627 signal_identifier = "rssi";
1630 while (g_at_result_iter_open_list(&iter)) {
1631 /* Reset invalid default value for every token */
1634 if (!g_at_result_iter_next_string(&iter, &str))
1637 if (!g_at_result_iter_open_list(&iter))
1640 while (g_at_result_iter_next_range(&iter, &tmp_min, &tmp_max)) {
1641 if (tmp_min != tmp_max) {
1648 if (!g_at_result_iter_close_list(&iter))
1651 if (!g_at_result_iter_close_list(&iter))
1654 if (g_str_equal(signal_identifier, str) == TRUE) {
1655 nd->signal_index = index;
1656 nd->signal_min = min;
1657 nd->signal_max = max;
1658 nd->signal_invalid = invalid;
1664 if (nd->vendor == OFONO_VENDOR_TELIT)
1665 g_at_result_iter_close_list(&iter);
1667 if (nd->signal_index == 0)
1670 g_at_chat_send(nd->chat, "AT+CMER=?", cmer_prefix,
1671 at_cmer_query_cb, netreg, NULL);
1676 ofono_error("This driver is not setup with Signal Strength reporting"
1677 " via CIND indications, please write proper netreg"
1678 " handling for this device");
1680 ofono_netreg_remove(netreg);
1683 static void at_creg_set_cb(gboolean ok, GAtResult *result, gpointer user_data)
1685 struct ofono_netreg *netreg = user_data;
1686 struct netreg_data *nd = ofono_netreg_get_data(netreg);
1689 ofono_error("Unable to initialize Network Registration");
1690 ofono_netreg_remove(netreg);
1694 switch (nd->vendor) {
1695 case OFONO_VENDOR_PHONESIM:
1696 g_at_chat_register(nd->chat, "+CSQ:",
1697 csq_notify, FALSE, netreg, NULL);
1699 case OFONO_VENDOR_CALYPSO:
1700 g_at_chat_send(nd->chat, "AT%CSQ=1", none_prefix,
1702 g_at_chat_register(nd->chat, "%CSQ:", calypso_csq_notify,
1703 FALSE, netreg, NULL);
1705 case OFONO_VENDOR_OPTION_HSO:
1706 g_at_chat_send(nd->chat, "AT_OSSYS=1", none_prefix,
1708 g_at_chat_send(nd->chat, "AT_OSQI=1", none_prefix,
1710 g_at_chat_register(nd->chat, "_OSIGQ:", option_osigq_notify,
1711 FALSE, netreg, NULL);
1713 g_at_chat_send(nd->chat, "AT_OSSYS?", none_prefix,
1715 g_at_chat_send(nd->chat, "AT_OSQI?", none_prefix,
1718 /* Register for network time update reports */
1719 g_at_chat_register(nd->chat, "+CTZV:", ctzv_notify,
1720 FALSE, netreg, NULL);
1721 g_at_chat_send(nd->chat, "AT+CTZR=1", none_prefix,
1724 case OFONO_VENDOR_MBM:
1725 /* Enable network registration updates */
1726 g_at_chat_send(nd->chat, "AT*E2REG=1", none_prefix,
1728 g_at_chat_send(nd->chat, "AT*EREG=2", none_prefix,
1730 g_at_chat_send(nd->chat, "AT*EPSB=1", none_prefix,
1733 /* Register for network technology updates */
1734 g_at_chat_send(nd->chat, "AT*ERINFO=1", none_prefix,
1736 g_at_chat_register(nd->chat, "*ERINFO:", mbm_erinfo_notify,
1737 FALSE, netreg, NULL);
1739 /* Register for network time update reports */
1740 g_at_chat_register(nd->chat, "*ETZV:", mbm_etzv_notify,
1741 FALSE, netreg, NULL);
1742 g_at_chat_send(nd->chat, "AT*ETZR=2", none_prefix,
1745 g_at_chat_send(nd->chat, "AT+CIND=?", cind_prefix,
1746 cind_support_cb, netreg, NULL);
1748 case OFONO_VENDOR_GOBI:
1750 * Gobi devices don't support unsolicited notifications
1751 * of technology changes, but register a handle for
1752 * CNTI so we get notified by any query.
1754 g_at_chat_register(nd->chat, "*CNTI:", gobi_cnti_notify,
1755 FALSE, netreg, NULL);
1757 case OFONO_VENDOR_NOVATEL:
1759 * Novatel doesn't support unsolicited notifications
1760 * of technology changes, but register a handle for
1761 * CNTI so we get notified by any query.
1763 g_at_chat_register(nd->chat, "$CNTI:", nw_cnti_notify,
1764 FALSE, netreg, NULL);
1766 case OFONO_VENDOR_HUAWEI:
1767 /* Register for RSSI reports */
1768 g_at_chat_register(nd->chat, "^RSSI:", huawei_rssi_notify,
1769 FALSE, netreg, NULL);
1771 /* Register for system mode reports */
1772 g_at_chat_register(nd->chat, "^MODE:", huawei_mode_notify,
1773 FALSE, netreg, NULL);
1775 /* Register for network time reports */
1776 g_at_chat_register(nd->chat, "^NWTIME:", huawei_nwtime_notify,
1777 FALSE, netreg, NULL);
1779 case OFONO_VENDOR_IFX:
1780 /* Register for specific signal strength reports */
1781 g_at_chat_register(nd->chat, "+XCIEV:", ifx_xciev_notify,
1782 FALSE, netreg, NULL);
1783 g_at_chat_register(nd->chat, "+XCSQ:", ifx_xcsq_notify,
1784 FALSE, netreg, NULL);
1785 g_at_chat_send(nd->chat, "AT+XCSQ=1", none_prefix,
1787 g_at_chat_send(nd->chat, "AT+XMER=1", none_prefix,
1790 /* Register for home zone reports */
1791 g_at_chat_register(nd->chat, "+XHOMEZR:", ifx_xhomezr_notify,
1792 FALSE, netreg, NULL);
1793 g_at_chat_send(nd->chat, "AT+XHOMEZR=1", none_prefix,
1796 /* Register for network time update reports */
1797 g_at_chat_register(nd->chat, "+CTZV:", ifx_ctzv_notify,
1798 FALSE, netreg, NULL);
1799 g_at_chat_register(nd->chat, "+CTZDST:", ifx_ctzdst_notify,
1800 FALSE, netreg, NULL);
1801 g_at_chat_send(nd->chat, "AT+CTZR=1", none_prefix,
1804 case OFONO_VENDOR_ZTE:
1805 /* Register for network time update reports */
1806 g_at_chat_register(nd->chat, "+CTZV:", ctzv_notify,
1807 FALSE, netreg, NULL);
1808 g_at_chat_send(nd->chat, "AT+CTZR=1", none_prefix,
1811 case OFONO_VENDOR_ICERA:
1812 /* Register for network technology updates */
1813 g_at_chat_register(nd->chat, "%NWSTATE:", icera_nwstate_notify,
1814 FALSE, netreg, NULL);
1815 g_at_chat_send(nd->chat, "AT%NWSTATE=1", none_prefix,
1818 /* Register for radio access technology updates */
1819 g_at_chat_send(nd->chat, "AT*TRATD=1", none_prefix,
1822 /* Register for network time update reports */
1823 g_at_chat_register(nd->chat, "*TLTS:", tlts_notify,
1824 FALSE, netreg, NULL);
1825 g_at_chat_send(nd->chat, "AT*TLTS=1", none_prefix,
1828 case OFONO_VENDOR_NOKIA:
1829 case OFONO_VENDOR_SAMSUNG:
1830 case OFONO_VENDOR_SIMCOM:
1831 /* Signal strength reporting via CIND is not supported */
1834 g_at_chat_send(nd->chat, "AT+CIND=?", cind_prefix,
1835 cind_support_cb, netreg, NULL);
1839 g_at_chat_register(nd->chat, "+CREG:",
1840 creg_notify, FALSE, netreg, NULL);
1841 ofono_netreg_register(netreg);
1844 static void at_creg_test_cb(gboolean ok, GAtResult *result, gpointer user_data)
1846 struct ofono_netreg *netreg = user_data;
1847 struct netreg_data *nd = ofono_netreg_get_data(netreg);
1856 g_at_result_iter_init(&iter, result);
1859 if (!g_at_result_iter_next(&iter, "+CREG:"))
1862 if (!g_at_result_iter_open_list(&iter))
1865 while (g_at_result_iter_next_range(&iter, &range[0], &range[1])) {
1866 if (1 >= range[0] && 1 <= range[1])
1868 if (2 >= range[0] && 2 <= range[1])
1872 g_at_result_iter_close_list(&iter);
1875 g_at_chat_send(nd->chat, "AT+CREG=2", none_prefix,
1876 at_creg_set_cb, netreg, NULL);
1881 g_at_chat_send(nd->chat, "AT+CREG=1", none_prefix,
1882 at_creg_set_cb, netreg, NULL);
1887 ofono_error("Unable to initialize Network Registration");
1888 ofono_netreg_remove(netreg);
1891 static int at_netreg_probe(struct ofono_netreg *netreg, unsigned int vendor,
1894 GAtChat *chat = data;
1895 struct netreg_data *nd;
1897 nd = g_new0(struct netreg_data, 1);
1899 nd->chat = g_at_chat_clone(chat);
1900 nd->vendor = vendor;
1909 nd->time.utcoff = 0;
1910 ofono_netreg_set_data(netreg, nd);
1912 g_at_chat_send(nd->chat, "AT+CREG=?", creg_prefix,
1913 at_creg_test_cb, netreg, NULL);
1918 static void at_netreg_remove(struct ofono_netreg *netreg)
1920 struct netreg_data *nd = ofono_netreg_get_data(netreg);
1922 if (nd->nitz_timeout)
1923 g_source_remove(nd->nitz_timeout);
1925 ofono_netreg_set_data(netreg, NULL);
1927 g_at_chat_unref(nd->chat);
1931 static struct ofono_netreg_driver driver = {
1933 .probe = at_netreg_probe,
1934 .remove = at_netreg_remove,
1935 .registration_status = at_registration_status,
1936 .current_operator = at_current_operator,
1937 .list_operators = at_list_operators,
1938 .register_auto = at_register_auto,
1939 .register_manual = at_register_manual,
1940 .strength = at_signal_strength,
1943 void at_netreg_init(void)
1945 ofono_netreg_driver_register(&driver);
1948 void at_netreg_exit(void)
1950 ofono_netreg_driver_unregister(&driver);