imc-pr3-desc: Implement setup_pdp entry point
authorGuillaume Zajac <guillaume.zajac@linux.intel.com>
Wed, 10 Oct 2012 09:35:00 +0000 (11:35 +0200)
committerAuke Kok <auke-jan.h.kok@intel.com>
Fri, 8 Feb 2013 20:25:53 +0000 (12:25 -0800)
src/desc_imc_pr3.c

index 135c110..b40698d 100644 (file)
@@ -58,6 +58,8 @@
 #define CHANNEL_PS             3
 #define CHANNEL_SAT            2
 #define CHANNEL_SS             2
+#define CHANNEL_DATA_1         6
+#define CHANNEL_DATA_2         7
 #define CHANNEL_NONE           -1
 
 struct custom_data {
@@ -205,12 +207,224 @@ static TReturn hal_link_object_channel(CoreObject *object)
        return ret;
 }
 
+static guint register_gio_watch(TcoreHal *h, int fd, void *callback)
+{
+       GIOChannel *channel = NULL;
+       guint source;
+
+       if (fd < 0 || !callback)
+               return 0;
+
+       channel = g_io_channel_unix_new(fd);
+       source = g_io_add_watch(channel, G_IO_IN, (GIOFunc) callback, h);
+       g_io_channel_unref(channel);
+       channel = NULL;
+
+       return source;
+}
+
+static int create_tun(const char **interface)
+{
+       GIOChannel *channel;
+       struct ifreq ifr;
+       int fd, err;
+
+       fd = open("/dev/net/tun", O_RDWR);
+       if (fd < 0)
+               return fd;
+
+       memset(&ifr, 0, sizeof(ifr));
+       ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
+       strcpy(ifr.ifr_name, "gprs%d");
+
+       err = ioctl(fd, TUNSETIFF, (void *) &ifr);
+       if (err < 0) {
+               close(fd);
+               return -1;
+       }
+
+       *interface = g_strdup(ifr.ifr_name);
+
+       channel = g_io_channel_unix_new(fd);
+       if (channel == NULL) {
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
+/*
+ * This function is reading data from /dev/net/tun and sending it to logical
+ * HAL bound to DATA multiplexed channel
+ */
+static gboolean on_recv_data_message(GIOChannel *channel, GIOCondition condition, gpointer data)
+{
+       TcoreHal *hal = data;
+       struct custom_data *custom;
+       char buf[BUF_LEN_MAX];
+       int n = 0;
+
+       custom = tcore_hal_ref_user_data(hal);
+       memset(buf, 0, BUF_LEN_MAX);
+       n = fd_read(custom->hal_fd, buf, BUF_LEN_MAX);
+       if (n < 0) {
+               err("fd_read error. return_valute = %d", n);
+               return TRUE;
+       }
+
+       msg("=== TX %s data DUMP =====", tcore_hal_get_name(hal));
+       util_hex_dump("          ", n, buf);
+       msg("=== TX %s data DUMP =====", tcore_hal_get_name(hal));
+
+       /* Send to cmux data channel for encoding */
+       tcore_hal_send_data(hal, n, buf);
+
+       return TRUE;
+}
+
+/*
+ * This function is receiving data from logical HAL bound to DATA multiplexed
+ * channel and writing it to /dev/net/tun
+ */
+static void on_hal_recv(TcoreHal *hal, unsigned int data_len, const void *data, void *user_data)
+{
+       int ret;
+       struct custom_data *cdata;
+       cdata = tcore_hal_ref_user_data(hal);
+
+       if (!cdata) {
+               err("hal user data is NULL");
+               return;
+       }
+
+       ret = fd_write(cdata->hal_fd, (void *)data, data_len);
+       if(ret < 0)
+               err("fd_write failed");
+
+       msg("=== RX %s data DUMP =====", tcore_hal_get_name(hal));
+       util_hex_dump("          ", data_len, data);
+       msg("=== RX %s data DUMP =====", tcore_hal_get_name(hal));
+}
+
+static void on_response_setup_pdp(TcorePending *p, int data_len, const void *data, void *user_data)
+{
+       TcoreHal *hal = user_data;
+       const TcoreATResponse *resp = data;
+       const char *interface = NULL;
+       struct custom_data *cdata = tcore_hal_ref_user_data(hal);
+       CoreObject *co = tcore_pending_ref_core_object(p);
+       TcoreHalSetupPDPCallBack func = (TcoreHalSetupPDPCallBack)cdata->cb;
+
+       dbg("Entered");
+
+       if (resp->success) {
+               dbg("Response Ok");
+
+               cdata->hal_fd = create_tun(&interface);
+               if (cdata->hal_fd < 0) {
+                       func(co, NULL, cdata->cb_data);
+
+                       g_free(cdata);
+                       cdata = NULL;
+
+                       return;
+               }
+
+               dbg("interface: %s", interface);
+
+               cdata->watch_id= register_gio_watch(hal, cdata->hal_fd, on_recv_data_message);
+               tcore_hal_set_mode(hal, TCORE_HAL_MODE_DATA);
+               tcore_hal_add_recv_callback(hal, on_hal_recv, NULL);
+
+               func(co, interface, cdata->cb_data);
+
+               return;
+       }
+
+       func(co, NULL, cdata->cb_data);
+       g_free(cdata);
+
+       dbg("Response NOk");
+
+       return;
+}
+
+static TReturn hal_setup_pdp(CoreObject *co, TcoreHalSetupPDPCallBack func,
+                               void *user_data, unsigned int cid)
+{
+       TcorePending *pending = NULL;
+       TcoreHal *hal = NULL;
+       char *cmd_str = NULL;
+       struct custom_data *cdata;
+
+       dbg("entry");
+
+       if (cid == 1)
+               hal = tcore_cmux_get_hal_channel(CHANNEL_DATA_1);
+       else if (cid == 2)
+               hal = tcore_cmux_get_hal_channel(CHANNEL_DATA_2);
+
+       if (hal == NULL) {
+               err("Fail to get channel data");
+               return TCORE_RETURN_FAILURE;
+       }
+
+       /*
+        * If data call was previously UP, hal was in MODE_DATA
+        * Set it back to MODE_AT to configure the channel and
+        * remove the hal receive callback.
+        */
+       if (tcore_hal_get_mode(hal) == TCORE_HAL_MODE_DATA) {
+               cdata = tcore_hal_ref_user_data(hal);
+
+               if (cdata->hal_fd) {
+                       close(cdata->hal_fd);
+                       cdata->hal_fd = -1;
+               }
+
+               g_source_remove(cdata->watch_id);
+               g_free(cdata);
+               cdata = NULL;
+
+               dbg("Set MODE_AT");
+               tcore_hal_set_mode(hal, TCORE_HAL_MODE_AT);
+               dbg("Remove old reveice cb");
+               tcore_hal_remove_recv_callback(hal, on_hal_recv);
+        }
+
+       cdata = g_new0(struct custom_data, 1);
+
+       cdata->cb = (void *)func;
+       cdata->cb_data = user_data;
+
+       tcore_hal_link_user_data(hal, cdata);
+
+       cmd_str = g_strdup_printf("AT+CGDATA=\"M-RAW_IP\",%d", cid);
+       pending = tcore_at_pending_new(co, cmd_str, NULL, TCORE_AT_NO_RESULT, on_response_setup_pdp, hal);
+       g_free(cmd_str);
+
+       if (pending == NULL) {
+               err("Fail to create AT+CGDATA pending request");
+
+               g_free(cdata);
+
+               return TCORE_RETURN_FAILURE;
+       }
+
+       tcore_hal_send_request(hal, pending);
+
+       return TCORE_RETURN_SUCCESS;
+}
+
 static struct tcore_hal_operations hops =
 {
        .power = hal_power,
        .send = hal_send,
        .set_sound_path = pr3_audio_set_sound_path,
        .link_object_channel = hal_link_object_channel,
+       .setup_pdp = hal_setup_pdp,
 };
 
 static gboolean on_recv_tty_message(GIOChannel *channel, GIOCondition condition, gpointer data)
@@ -236,22 +450,6 @@ static gboolean on_recv_tty_message(GIOChannel *channel, GIOCondition condition,
        return TRUE;
 }
 
-static guint register_gio_watch(TcoreHal *h, int fd, void *callback)
-{
-       GIOChannel *channel = NULL;
-       guint source;
-
-       if (fd < 0 || !callback)
-               return 0;
-
-       channel = g_io_channel_unix_new(fd);
-       source = g_io_add_watch(channel, G_IO_IN, (GIOFunc) callback, h);
-       g_io_channel_unref(channel);
-       channel = NULL;
-
-       return source;
-}
-
 static gboolean on_load()
 {
        dbg("I'm load!");