[PATCH 19/19] ubloxmodem: add routed mode support
by dragos@endocode.com
From: Dongsu Park <dongsu(a)endocode.com>
Routed mode needs a different treatment than bridged mode:
* UIPCONF needs to be used for reading the interface ip configuratuion.
The spec says that DHCP should work on that interface but it doesn't. So
we read the first ip in the dhcp range and use that.
* CGCONTRDP: only APN and DNS configuration is read
---
drivers/ubloxmodem/gprs-context.c | 151 +++++++++++++++++++++++++++++++++++++-
1 file changed, 150 insertions(+), 1 deletion(-)
diff --git a/drivers/ubloxmodem/gprs-context.c b/drivers/ubloxmodem/gprs-context.c
index bc100d6..4040a07 100644
--- a/drivers/ubloxmodem/gprs-context.c
+++ b/drivers/ubloxmodem/gprs-context.c
@@ -43,6 +43,7 @@
static const char *none_prefix[] = { NULL };
static const char *cgcontrdp_prefix[] = { "+CGCONTRDP:", NULL };
+static const char *uipconf_prefix[] = { "+UIPCONF:", NULL };
struct gprs_context_data {
GAtChat *chat;
@@ -250,6 +251,65 @@ static void cgcontrdp_bridge_cb(gboolean ok, GAtResult *result, gpointer user_da
CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
}
+static void cgcontrdp_router_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_gprs_context *gc = user_data;
+ struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+ GAtResultIter iter;
+
+ const char *dns[2+1] = { NULL, NULL, NULL };
+ const char *apn = NULL;
+
+ DBG("ok %d", ok);
+
+ if (!ok) {
+ callback_with_error(gcd, result);
+
+ return;
+ }
+
+ g_at_result_iter_init(&iter, result);
+
+ while (g_at_result_iter_next(&iter, "+CGCONTRDP:")) {
+ /* skip cid, bearer_id */
+ g_at_result_iter_skip_next(&iter);
+ g_at_result_iter_skip_next(&iter);
+
+ /* read apn */
+ if (!g_at_result_iter_next_string(&iter, &apn))
+ break;
+
+ /* skip laddrnetmask, gw */
+ g_at_result_iter_skip_next(&iter);
+ g_at_result_iter_skip_next(&iter);
+
+ /* read dns servers */
+ if (!g_at_result_iter_next_string(&iter, &dns[0]))
+ break;
+
+ if (!g_at_result_iter_next_string(&iter, &dns[1]))
+ break;
+ }
+
+ set_gprs_context_interface(gc);
+
+ if (dns[0])
+ ofono_gprs_context_set_ipv4_dns_servers(gc, dns);
+
+ if (gcd->active_context == ublox_data.default_context_id) {
+ /*
+ * Only for automatic default context: the APN set by the user
+ * might not be the correct one because the default context was
+ * used instead.
+ */
+ ofono_gprs_context_set_apn(gc, apn);
+ strcpy(gcd->apn, apn);
+ }
+
+ CALLBACK_WITH_SUCCESS(gcd->cb, gcd->cb_data);
+ return;
+}
+
static int ublox_read_ip_config_bridge(struct ofono_gprs_context *gc)
{
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
@@ -262,11 +322,100 @@ static int ublox_read_ip_config_bridge(struct ofono_gprs_context *gc)
}
+static void read_uipconf_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_gprs_context *gc = user_data;
+ struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+ GAtResultIter iter;
+ const char *gw, *netmask, *ipaddr, *dhcp_range_start, *dhcp_range_end;
+ gboolean found = FALSE;
+ char buf[64];
+
+ DBG("ok %d", ok);
+
+ if (!ok) {
+ release_context_id(gcd->active_context);
+ callback_with_error(gcd, result);
+
+ return;
+ }
+
+ g_at_result_iter_init(&iter, result);
+
+ /* for example, +UIPCONF: entry looks like:
+ * +UIPCONF: "192.168.1.1","255.255.255.0","192.168.1.100",
+ * "192.168.1.100","fe80::48a5:b2ff:fe6f:5f86/64"
+ */
+ while (g_at_result_iter_next(&iter, "+UIPCONF:")) {
+ if (!g_at_result_iter_next_string(&iter, &gw))
+ continue;
+
+ if (!g_at_result_iter_next_string(&iter, &netmask))
+ continue;
+
+ if (!g_at_result_iter_next_string(&iter, &dhcp_range_start))
+ continue;
+
+ if (!g_at_result_iter_next_string(&iter, &dhcp_range_end))
+ continue;
+
+ /* skip other entries like IPv6 networks */
+ found = TRUE;
+ break;
+ }
+
+ if (!found)
+ goto error;
+
+ if (dhcp_range_start && dhcp_range_end) {
+ ipaddr = dhcp_range_start;
+ ofono_gprs_context_set_ipv4_address(gc, ipaddr, 1);
+ }
+
+ if (netmask)
+ ofono_gprs_context_set_ipv4_netmask(gc, netmask);
+
+ if (gw)
+ ofono_gprs_context_set_ipv4_gateway(gc, gw);
+
+ /* read ip configuration info */
+ snprintf(buf, sizeof(buf), "AT+CGCONTRDP");
+ if (g_at_chat_send(gcd->chat, buf, cgcontrdp_prefix,
+ cgcontrdp_router_cb, gc, NULL) > 0)
+ return;
+
+error:
+ CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data);
+}
+
+static int ublox_read_ip_config_router(struct ofono_gprs_context *gc)
+{
+ struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+ char buf[64];
+
+ /* read ip configuration info */
+ snprintf(buf, sizeof(buf), "AT+UIPCONF?");
+ return g_at_chat_send(gcd->chat, buf, uipconf_prefix,
+ read_uipconf_cb, gc, NULL);
+
+}
+
static void ublox_post_activation(struct ofono_gprs_context *gc)
{
+ struct ofono_modem *modem;
+ const char *network_mode;
struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc);
+ int ret = 0;
+
+ modem = ofono_gprs_context_get_modem(gc);
+ network_mode = ofono_modem_get_string(modem, "NetworkMode");
+
+ if (g_str_equal(network_mode, "routed"))
+ ret = ublox_read_ip_config_router(gc) ;
+ else
+ ret = ublox_read_ip_config_bridge(gc);
- if (ublox_read_ip_config_bridge(gc) < 0)
+ if (ret <= 0)
CALLBACK_WITH_FAILURE(gcd->cb, gcd->cb_data);
}
--
2.5.0
4 years, 10 months
[PATCH 18/19] plugins/ublox: read network mode
by dragos@endocode.com
From: Dongsu Park <dongsu(a)endocode.com>
Read network mode into modem string. This will let the gprs-context
drive know what to do.
---
plugins/ublox.c | 47 ++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 42 insertions(+), 5 deletions(-)
diff --git a/plugins/ublox.c b/plugins/ublox.c
index 76f7fcf..9cfba33 100644
--- a/plugins/ublox.c
+++ b/plugins/ublox.c
@@ -42,6 +42,7 @@
#include <drivers/atmodem/atutil.h>
#include <drivers/atmodem/vendor.h>
+static const char *ubmconf_prefix[] = { "+UBMCONF:", NULL };
static const char *none_prefix[] = { NULL };
enum supported_models {
@@ -52,11 +53,17 @@ enum supported_models {
TOBYL2_HIGH_THROUGHPUT_MODE = 1146,
};
+enum ublox_net_mode {
+ UBLOX_TOBYL2_NET_MODE_ROUTER = 1,
+ UBLOX_TOBYL2_NET_MODE_BRIDGE = 2,
+};
+
struct ublox_data {
GAtChat *modem;
GAtChat *aux;
int model_id;
enum ofono_vendor vendor_family;
+ enum ublox_net_mode net_mode;
};
static void ublox_debug(const char *str, void *user_data)
@@ -93,6 +100,39 @@ static void ublox_remove(struct ofono_modem *modem)
g_free(data);
}
+static void read_ubmconf_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = (struct ofono_modem *) user_data;
+ struct ublox_data *data = ofono_modem_get_data(modem);
+ int mode = 0;
+ GAtResultIter iter;
+
+ g_at_result_iter_init(&iter, result);
+
+ while (!g_at_result_iter_next(&iter, "+UBMCONF:"))
+ ; /* skip every other line that is not UBMCONF */
+
+ g_at_result_iter_next_number(&iter, &mode);
+
+ data->net_mode = mode;
+ DBG("mode=%d", mode);
+ if (mode == 1)
+ ofono_modem_set_string(modem, "NetworkMode", "routed");
+ else if (mode == 2)
+ ofono_modem_set_string(modem, "NetworkMode", "bridged");
+}
+
+static void read_net_mode(struct ofono_modem *modem)
+{
+ struct ublox_data *data = ofono_modem_get_data(modem);
+
+ if (!data->aux)
+ return;
+
+ g_at_chat_send(data->aux, "AT+UBMCONF?",
+ ubmconf_prefix, read_ubmconf_cb, modem, NULL);
+}
+
static GAtChat *open_device(struct ofono_modem *modem,
const char *key, char *debug)
{
@@ -142,11 +182,6 @@ static void cfun_enable(gboolean ok, GAtResult *result, gpointer user_data)
return;
}
- if (data->model_id == TOBYL2_HIGH_THROUGHPUT_MODE)
- /* use bridged mode until routed mode support is added */
- g_at_chat_send(data->aux, "AT+UBMCONF=2", none_prefix,
- NULL, NULL, NULL);
-
ofono_modem_set_powered(modem, TRUE);
}
@@ -207,6 +242,8 @@ static int ublox_enable(struct ofono_modem *modem)
g_at_chat_send(data->aux, "ATE0 +CMEE=1", none_prefix,
NULL, NULL, NULL);
+ read_net_mode(modem);
+
g_at_chat_send(data->aux, "AT+CFUN=4", none_prefix,
cfun_enable, modem, NULL);
--
2.5.0
4 years, 10 months
[PATCH 02/19] plugins/udevng: support different interface strings to detect TOBY series
by dragos@endocode.com
From: Dongsu Park <dongsu(a)endocode.com>
Each modem expresses their interfaces with its own interface string,
which is composed of 3 different USB attributes:
"bInterfaceClass/bInterfaceSubClass/bInterfaceProtocol".
While the old models like LISA support only "2/2/1" for modem
interfaces, TOBY-L2 also supports an unique string for NetworkInterface
for each profile.
* low-medium throughput profile : 2/6/0
* fairly backward-compatible profile : 10/0/0
* high throughput profile : 224/1/3
Besides the condition for checking NULL for mdm/aux/net should be relaxed
a little bit.
---
plugins/udevng.c | 22 +++++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/plugins/udevng.c b/plugins/udevng.c
index 52b667e..2170c90 100644
--- a/plugins/udevng.c
+++ b/plugins/udevng.c
@@ -838,7 +838,7 @@ static gboolean setup_quectel(struct modem_info *modem)
static gboolean setup_ublox(struct modem_info *modem)
{
- const char *aux = NULL, *mdm = NULL;
+ const char *aux = NULL, *mdm = NULL, *net = NULL;
GSList *list;
DBG("%s", modem->syspath);
@@ -857,21 +857,37 @@ static gboolean setup_ublox(struct modem_info *modem)
mdm = info->devnode;
if (aux != NULL)
break;
+ /*
+ * "2/2/1"
+ * - a common modem interface both for older models like LISA,
+ * and for newer models like TOBY.
+ * For TOBY-L2, NetworkInterface can be detected for each profile:
+ * - low-medium throughput profile : 2/6/0
+ * - fairly backward-compatible profile : 10/0/0
+ * - high throughput profile : 224/1/3
+ * */
} else if (g_strcmp0(info->interface, "2/2/1") == 0) {
if (g_strcmp0(info->number, "02") == 0)
aux = info->devnode;
else if (g_strcmp0(info->number, "00") == 0)
mdm = info->devnode;
+ } else if (g_strcmp0(info->interface, "2/6/0") == 0 ||
+ g_strcmp0(info->interface, "10/0/0") == 0 ||
+ g_strcmp0(info->interface, "224/1/3") == 0) {
+ net = info->devnode;
}
}
- if (aux == NULL || mdm == NULL)
+ /* Abort only if both interfaces are NULL, as it's highly possible that
+ * only one of 2 interfaces is available for U-blox modem. */
+ if (aux == NULL && mdm == NULL)
return FALSE;
- DBG("aux=%s modem=%s", aux, mdm);
+ DBG("aux=%s modem=%s net=%s", aux, mdm, net);
ofono_modem_set_string(modem->modem, "Aux", aux);
ofono_modem_set_string(modem->modem, "Modem", mdm);
+ ofono_modem_set_string(modem->modem, "NetworkInterface", net);
return TRUE;
}
--
2.5.0
4 years, 10 months
[PATCH 01/19] plugins/udevng: support the U-Blox TOBY-L2 series
by dragos@endocode.com
From: Dongsu Park <dongsu(a)endocode.com>
The newest generation of U-Blox TOBY-L2 series can be detected with
VID 0x1546 (the same as before), and one of the following PIDs:
* "0x1146" : high throughput profile
* "0x1141" : fairly back-compatible profile
* "0x1143" : low/medium throughput profile
This patch adds detection for high throughput mode.
---
plugins/udevng.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/plugins/udevng.c b/plugins/udevng.c
index e43d045..52b667e 100644
--- a/plugins/udevng.c
+++ b/plugins/udevng.c
@@ -1120,6 +1120,8 @@ static struct {
{ "samsung", "kalmia" },
{ "quectel", "option", "05c6", "9090" },
{ "ublox", "cdc_acm", "1546", "1102" },
+ { "ublox", "rndis_host", "1546", "1146" },
+ { "ublox", "cdc_acm", "1546", "1146" },
{ }
};
--
2.5.0
4 years, 10 months