aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTambet Ingo <tambet@gmail.com>2008-09-15 13:07:03 +0300
committerTambet Ingo <tambet@gmail.com>2008-09-15 13:07:03 +0300
commit1455c424c2a5b2fcb61163b2feb3a2aadc0bfad0 (patch)
treedeb3ef8c8276175d283459fc8ba79a90d44f9e14 /src
parentb4176325e5c51bc920366e4475c3c75bf1bc3757 (diff)
Implement smarter APN choosing.
If the APN chosen by user is already configured in card, use that. If not, find the highest used CID, the allowed range of CIDs and add new (or overwrite the highest one).
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);