aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mm-generic-gsm.c157
-rw-r--r--src/mm-generic-gsm.h3
2 files changed, 153 insertions, 7 deletions
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c
index d01b2e87..5035e3d5 100644
--- a/src/mm-generic-gsm.c
+++ b/src/mm-generic-gsm.c
@@ -41,6 +41,14 @@ mm_generic_gsm_new (const char *serial_device, const char *driver)
NULL));
}
+void
+mm_generic_gsm_set_cid (MMGenericGsm *modem, guint32 cid)
+{
+ g_return_if_fail (MM_IS_GENERIC_GSM (modem));
+
+ MM_GENERIC_GSM_GET_PRIVATE (modem)->cid = cid;
+}
+
guint32
mm_generic_gsm_get_cid (MMGenericGsm *modem)
{
@@ -717,6 +725,8 @@ scan (MMModemGsmNetwork *modem,
mm_serial_queue_command (MM_SERIAL (modem), "+COPS=?", 60, scan_done, info);
}
+/* SetApn */
+
static void
set_apn_done (MMSerial *serial,
GString *response,
@@ -728,29 +738,162 @@ set_apn_done (MMSerial *serial,
if (error)
info->error = g_error_copy (error);
else
- MM_GENERIC_GSM_GET_PRIVATE (serial)->cid = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "CID"));
+ mm_generic_gsm_set_cid (MM_GENERIC_GSM (serial),
+ GPOINTER_TO_UINT (mm_callback_info_get_data (info, "cid")));
mm_callback_info_schedule (info);
}
static void
+cid_range_read (MMSerial *serial,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ guint32 cid = 0;
+
+ if (error)
+ info->error = g_error_copy (error);
+ else if (g_str_has_prefix (response->str, "+CGDCONT: ")) {
+ GRegex *r;
+ GMatchInfo *match_info;
+
+ r = g_regex_new ("\\+CGDCONT: \\((\\d+)-(\\d+)\\),\"(\\S+)\"",
+ G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW,
+ 0, &info->error);
+ if (r) {
+ g_regex_match_full (r, response->str, response->len, 0, 0, &match_info, &info->error);
+ while (cid == 0 && g_match_info_matches (match_info)) {
+ char *tmp;
+
+ tmp = g_match_info_fetch (match_info, 3);
+ if (!strcmp (tmp, "IP")) {
+ int max_cid;
+ int highest_cid = GPOINTER_TO_INT (mm_callback_info_get_data (info, "highest-cid"));
+
+ g_free (tmp);
+
+ tmp = g_match_info_fetch (match_info, 2);
+ max_cid = atoi (tmp);
+
+ if (highest_cid < max_cid)
+ cid = highest_cid + 1;
+ else
+ cid = highest_cid;
+ }
+
+ g_free (tmp);
+ g_match_info_next (match_info, NULL);
+ }
+
+ if (cid == 0)
+ /* Choose something */
+ cid = 1;
+ }
+ } else
+ info->error = g_error_new_literal (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Could not parse the response");
+
+ if (info->error)
+ mm_callback_info_schedule (info);
+ else {
+ const char *apn = (const char *) mm_callback_info_get_data (info, "apn");
+ char *command;
+
+ mm_callback_info_set_data (info, "cid", GUINT_TO_POINTER (cid), NULL);
+
+ command = g_strdup_printf ("+CGDCONT=%d, \"IP\", \"%s\"", cid, apn);
+ mm_serial_queue_command (serial, command, 3, set_apn_done, info);
+ g_free (command);
+ }
+}
+
+static void
+existing_apns_read (MMSerial *serial,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ gboolean found = FALSE;
+
+ if (error)
+ info->error = g_error_copy (error);
+ else if (g_str_has_prefix (response->str, "+CGDCONT: ")) {
+ GRegex *r;
+ GMatchInfo *match_info;
+
+ r = g_regex_new ("\\+CGDCONT: (\\d+)\\s*,\"(\\S+)\",\"(\\S+)\",\"(\\S+)\"",
+ G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW,
+ 0, &info->error);
+ if (r) {
+ const char *new_apn = (const char *) mm_callback_info_get_data (info, "apn");
+
+ g_regex_match_full (r, response->str, response->len, 0, 0, &match_info, &info->error);
+ while (!found && g_match_info_matches (match_info)) {
+ char *cid;
+ char *pdp_type;
+ char *apn;
+ int num_cid;
+
+ cid = g_match_info_fetch (match_info, 1);
+ num_cid = atoi (cid);
+ pdp_type = g_match_info_fetch (match_info, 2);
+ apn = g_match_info_fetch (match_info, 3);
+
+ if (!strcmp (apn, new_apn)) {
+ mm_generic_gsm_set_cid (MM_GENERIC_GSM (serial), (guint32) num_cid);
+ found = TRUE;
+ }
+
+ if (!found && !strcmp (pdp_type, "IP")) {
+ int highest_cid;
+
+ highest_cid = GPOINTER_TO_INT (mm_callback_info_get_data (info, "highest-cid"));
+ if (num_cid > highest_cid)
+ mm_callback_info_set_data (info, "highest-cid", GINT_TO_POINTER (num_cid), NULL);
+ }
+
+ g_free (cid);
+ g_free (pdp_type);
+ g_free (apn);
+ g_match_info_next (match_info, NULL);
+ }
+
+ g_match_info_free (match_info);
+ g_regex_unref (r);
+ }
+ } else
+ info->error = g_error_new_literal (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Could not parse the response");
+
+ if (found || info->error)
+ mm_callback_info_schedule (info);
+ else
+ /* APN not configured on the card. Get the allowed CID range */
+ mm_serial_queue_command (serial, "+CGDCONT=?", 3, cid_range_read, info);
+}
+
+static void
set_apn (MMModemGsmNetwork *modem,
const char *apn,
MMModemFn callback,
gpointer user_data)
{
MMCallbackInfo *info;
- char *command;
- guint cid = 1;
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
- mm_callback_info_set_data (info, "CID", GUINT_TO_POINTER (cid), NULL);
+ mm_callback_info_set_data (info, "apn", g_strdup (apn), g_free);
- command = g_strdup_printf ("+CGDCONT=%d, \"IP\", \"%s\"", cid, apn);
- mm_serial_queue_command (MM_SERIAL (modem), command, 3, set_apn_done, info);
- g_free (command);
+ /* Start by searching if the APN is already in card */
+ mm_serial_queue_command (MM_SERIAL (modem), "+CGDCONT?", 3, existing_apns_read, info);
}
+/* GetSignalQuality */
+
static void
get_signal_quality_done (MMSerial *serial,
GString *response,
diff --git a/src/mm-generic-gsm.h b/src/mm-generic-gsm.h
index e2afc006..621bad7f 100644
--- a/src/mm-generic-gsm.h
+++ b/src/mm-generic-gsm.h
@@ -26,6 +26,9 @@ GType mm_generic_gsm_get_type (void);
MMModem *mm_generic_gsm_new (const char *serial_device,
const char *driver);
+void mm_generic_gsm_set_cid (MMGenericGsm *modem,
+ guint32 cid);
+
guint32 mm_generic_gsm_get_cid (MMGenericGsm *modem);
void mm_generic_gsm_set_reg_status (MMGenericGsm *modem,
MMModemGsmNetworkRegStatus status);