From a1c47f975980a76151e38655d18abf95742f754a Mon Sep 17 00:00:00 2001 From: Guillaume Zajac Date: Wed, 10 Oct 2012 11:35:00 +0200 Subject: [PATCH] imc-pr3-desc: Implement setup_pdp entry point --- src/desc_imc_pr3.c | 230 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 214 insertions(+), 16 deletions(-) diff --git a/src/desc_imc_pr3.c b/src/desc_imc_pr3.c index 135c110..b40698d 100644 --- a/src/desc_imc_pr3.c +++ b/src/desc_imc_pr3.c @@ -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!"); -- 2.7.4