* [PATCH v3 1/2] stemodem: Add RTNL functionality managing CAIF Network Interfaces. @ 2010-11-03 18:40 Sjur =?unknown-8bit?q?Br=C3=A6ndeland?= 2010-11-03 18:40 ` [PATCH v3 2/2] stemodem: Update gprs-context to use rtnl to create/remove interfaces Sjur =?unknown-8bit?q?Br=C3=A6ndeland?= 2010-11-04 14:02 ` [PATCH v3 1/2] stemodem: Add RTNL functionality managing CAIF Network Interfaces Sjur =?unknown-8bit?q?Br=C3=A6ndeland?= 0 siblings, 2 replies; 3+ messages in thread From: Sjur =?unknown-8bit?q?Br=C3=A6ndeland?= @ 2010-11-03 18:40 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 11731 bytes --] From: Sjur Brændeland <sjur.brandeland@stericsson.com> --- Hi Marcel. I hope I have closed most of your review comments so far. I had a go at using g_io_chanel_write_chars, but couldn't make it work, and I (stubbornly ;-) do g_caif_devices = NULL, just in case someone choose to call caif_rtnl_init more than once. Makefile.am | 2 + drivers/stemodem/caif_rtnl.c | 382 ++++++++++++++++++++++++++++++++++++++++++ drivers/stemodem/caif_rtnl.h | 29 ++++ 3 files changed, 413 insertions(+), 0 deletions(-) create mode 100644 drivers/stemodem/caif_rtnl.c create mode 100644 drivers/stemodem/caif_rtnl.h diff --git a/Makefile.am b/Makefile.am index cd17fa2..aea91ce 100644 --- a/Makefile.am +++ b/Makefile.am @@ -226,6 +226,8 @@ builtin_sources += drivers/atmodem/atutil.h \ drivers/stemodem/stemodem.c \ drivers/stemodem/voicecall.c \ drivers/stemodem/radio-settings.c \ + drivers/stemodem/caif_rtnl.c \ + drivers/stemodem/caif_rtnl.h \ drivers/stemodem/gprs-context.c \ drivers/stemodem/caif_socket.h \ drivers/stemodem/if_caif.h diff --git a/drivers/stemodem/caif_rtnl.c b/drivers/stemodem/caif_rtnl.c new file mode 100644 index 0000000..82740ba --- /dev/null +++ b/drivers/stemodem/caif_rtnl.c @@ -0,0 +1,382 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2010 ST-Ericsson AB. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <fcntl.h> +#include <linux/rtnetlink.h> + +#include <glib.h> + +#include <ofono/log.h> + +#include "if_caif.h" +#include "caif_rtnl.h" + +#define NLMSG_TAIL(nmsg) \ + ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) + +struct iplink_req { + struct nlmsghdr n; + struct ifinfomsg i; + char pad[1024]; + + int request_id; + int type; + int conn_id; + gpointer user_data; + gboolean loop_enabled; + + char ifname[IF_NAMESIZE]; + int ifindex; + caif_rtnl_create_cb_t callback; +}; + +static GSList *pending_requests; +static guint32 rtnl_seqnr; +static guint rtnl_watch; +static GIOChannel *channel; + +static gboolean get_ifname(struct ifinfomsg *msg, int bytes, + const char **ifname) +{ + struct rtattr *attr; + + for (attr = IFLA_RTA(msg); RTA_OK(attr, bytes); + attr = RTA_NEXT(attr, bytes)) { + + if (attr->rta_type == IFLA_IFNAME && + ifname != NULL) { + + *ifname = RTA_DATA(attr); + return TRUE; + } + } + + return FALSE; +} + +static void store_newlink_param(struct iplink_req *req, unsigned short type, + int index, unsigned flags, + unsigned change, struct ifinfomsg *msg, + int bytes) +{ + const char *ifname = NULL; + + get_ifname(msg, bytes, &ifname); + strncpy(req->ifname, ifname, + sizeof(req->ifname)); + req->ifname[sizeof(req->ifname)-1] = '\0'; + req->ifindex = index; +} + +static int send_rtnl_req(struct iplink_req *req) +{ + struct sockaddr_nl addr; + int sk = g_io_channel_unix_get_fd(channel); + + memset(&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; + + return sendto(sk, req, req->n.nlmsg_len, 0, + (struct sockaddr *) &addr, sizeof(addr)); +} + +static struct iplink_req *find_request(guint32 seq) +{ + GSList *list; + + for (list = pending_requests; list; list = list->next) { + struct iplink_req *req = list->data; + + if (req->n.nlmsg_seq == seq) + return req; + } + + return NULL; +} + +static void rtnl_client_response(struct iplink_req *req, int result) +{ + + if (req->callback && req->n.nlmsg_type == RTM_NEWLINK) + req->callback(result, req->user_data, + req->ifname, req->ifindex); + + pending_requests = g_slist_remove(pending_requests, req); + g_free(req); +} + +static void parse_rtnl_message(void *buf, size_t len) +{ + struct ifinfomsg *msg; + struct iplink_req *req; + + while (len > 0) { + struct nlmsghdr *hdr = buf; + + if (!NLMSG_OK(hdr, len)) + break; + + if (hdr->nlmsg_type == RTM_NEWLINK) { + req = g_slist_nth_data(pending_requests, 0); + if (req == NULL) + break; + + msg = (struct ifinfomsg *) NLMSG_DATA(hdr); + store_newlink_param(req, msg->ifi_type, + msg->ifi_index, msg->ifi_flags, + msg->ifi_change, msg, + IFA_PAYLOAD(hdr)); + rtnl_client_response(req, 0); + return; + + } else if (hdr->nlmsg_type == NLMSG_ERROR) { + req = find_request(hdr->nlmsg_seq); + if (req == NULL) + break; + + DBG("nlmsg error req"); + rtnl_client_response(req, -1); + return; + } + + len -= hdr->nlmsg_len; + buf += hdr->nlmsg_len; + } +} + +static int add_attribute(struct nlmsghdr *n, int maxlen, int type, + const void *data, int datalen) +{ + int len = RTA_LENGTH(datalen); + struct rtattr *rta; + + if ((int)(NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len)) > maxlen) { + DBG("attribute to large for message %d %d %d\n", + n->nlmsg_len, len, maxlen); + return -1; + } + + rta = NLMSG_TAIL(n); + rta->rta_type = type; + rta->rta_len = len; + memcpy(RTA_DATA(rta), data, datalen); + n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); + + return 0; +} + +static int prep_rtnl_newlink_req(struct iplink_req *req) +{ + char type[] = "caif"; + struct rtattr *linkinfo; + struct rtattr *data; + + req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req->n.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; + req->n.nlmsg_type = RTM_NEWLINK; + req->n.nlmsg_seq = ++rtnl_seqnr; + req->i.ifi_family = AF_UNSPEC; + + linkinfo = NLMSG_TAIL(&req->n); + add_attribute(&req->n, sizeof(*req), IFLA_LINKINFO, + NULL, 0); + add_attribute(&req->n, sizeof(*req), IFLA_INFO_KIND, + type, strlen(type)); + data = NLMSG_TAIL(&req->n); + add_attribute(&req->n, sizeof(*req), IFLA_INFO_DATA, + NULL, 0); + + switch (req->type) { + + case IFLA_CAIF_IPV4_CONNID: + add_attribute(&req->n, sizeof(*req), + IFLA_CAIF_IPV4_CONNID, &req->conn_id, + sizeof(req->conn_id)); + break; + + case IFLA_CAIF_IPV6_CONNID: + add_attribute(&req->n, sizeof(*req), + IFLA_CAIF_IPV6_CONNID, &req->conn_id, + sizeof(req->conn_id)); + break; + + case __IFLA_CAIF_UNSPEC: + case IFLA_CAIF_LOOPBACK: + case __IFLA_CAIF_MAX: + DBG("unsupported linktype"); + return -EINVAL; + } + + if (req->loop_enabled) { + int loop = 1; + add_attribute(&req->n, sizeof(*req), + IFLA_CAIF_LOOPBACK, &loop, sizeof(loop)); + } + + data->rta_len = (void *)NLMSG_TAIL(&req->n) - (void *)data; + linkinfo->rta_len = (void *)NLMSG_TAIL(&req->n) - (void *)linkinfo; + + return 0; +} + +static void prep_rtnl_dellink_req(struct iplink_req *req, int ifindex) +{ + req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req->n.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; + req->n.nlmsg_type = RTM_DELLINK; + req->n.nlmsg_seq = ++rtnl_seqnr; + req->i.ifi_family = AF_UNSPEC; + req->i.ifi_index = ifindex; +} + +static gboolean netlink_event(GIOChannel *chan, + GIOCondition cond, gpointer data) +{ + unsigned char buf[4096]; + gsize len; + GIOError err; + + if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) { + rtnl_watch = 0; + return FALSE; + } + + memset(buf, 0, sizeof(buf)); + + err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf), &len); + if (err) { + if (err == G_IO_ERROR_AGAIN) + return TRUE; + rtnl_watch = 0; + return FALSE; + } + + parse_rtnl_message(buf, len); + + return TRUE; +} + +int caif_rtnl_init(void) +{ + struct sockaddr_nl addr; + int sk, err; + GError *gerr = NULL; + + sk = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); + if (sk < 0) + return sk; + + memset(&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; + addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE; + + err = bind(sk, (struct sockaddr *) &addr, sizeof(addr)); + if (err < 0) { + close(sk); + return err; + } + + channel = g_io_channel_unix_new(sk); + g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, &gerr); + g_io_channel_set_encoding(channel, NULL, &gerr); + g_io_channel_set_buffered(channel, TRUE); + g_io_channel_set_close_on_unref(channel, TRUE); + + rtnl_watch = g_io_add_watch(channel, + G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR, + netlink_event, NULL); + pending_requests = NULL; + + return 0; +} + +void caif_rtnl_exit(void) +{ + GSList *list; + + if (rtnl_watch > 0) + g_source_remove(rtnl_watch); + + g_io_channel_unref(channel); + + for (list = pending_requests; list; list = list->next) { + struct iplink_req *req = list->data; + g_free(req); + } + + g_slist_free(pending_requests); +} + + +int caif_rtnl_create_interface(gpointer user_data, int type, int connid, + gboolean loop, caif_rtnl_create_cb_t cb) +{ + int err; + struct iplink_req *req; + + req = g_try_new0(struct iplink_req, 1); + if (req == NULL) + return -ENOMEM; + + req->user_data = user_data; + req->type = type; + req->conn_id = connid; + req->loop_enabled = loop; + req->callback = cb; + + err = prep_rtnl_newlink_req(req); + if (err < 0) + goto error; + + err = send_rtnl_req(req); + if (err < 0) + goto error; + + pending_requests = g_slist_append(pending_requests, req); + return 0; +error: + g_free(req); + return err; + +} + +int caif_rtnl_delete_interface(int ifid) +{ + struct iplink_req req; + int err; + memset(&req, 0, sizeof(req)); + prep_rtnl_dellink_req(&req, ifid); + + err = send_rtnl_req(&req); + if (err < 0) + return err; + + return 0; +} diff --git a/drivers/stemodem/caif_rtnl.h b/drivers/stemodem/caif_rtnl.h new file mode 100644 index 0000000..8eb1e5f --- /dev/null +++ b/drivers/stemodem/caif_rtnl.h @@ -0,0 +1,29 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2010 ST-Ericsson AB. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +typedef void (*caif_rtnl_create_cb_t) (int result, gpointer user_data, + char *ifname, int ifindex); + +extern int caif_rtnl_create_interface(gpointer user_data, int type, int connid, + gboolean loop, caif_rtnl_create_cb_t cb); +extern int caif_rtnl_delete_interface(int ifid); + +extern int caif_rtnl_init(void); +extern void caif_rtnl_exit(void); -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH v3 2/2] stemodem: Update gprs-context to use rtnl to create/remove interfaces. 2010-11-03 18:40 [PATCH v3 1/2] stemodem: Add RTNL functionality managing CAIF Network Interfaces Sjur =?unknown-8bit?q?Br=C3=A6ndeland?= @ 2010-11-03 18:40 ` Sjur =?unknown-8bit?q?Br=C3=A6ndeland?= 2010-11-04 14:02 ` [PATCH v3 1/2] stemodem: Add RTNL functionality managing CAIF Network Interfaces Sjur =?unknown-8bit?q?Br=C3=A6ndeland?= 1 sibling, 0 replies; 3+ messages in thread From: Sjur =?unknown-8bit?q?Br=C3=A6ndeland?= @ 2010-11-03 18:40 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 12037 bytes --] From: Sjur Brændeland <sjur.brandeland@stericsson.com> --- drivers/stemodem/gprs-context.c | 207 +++++++++++++++++++++++++-------------- 1 files changed, 135 insertions(+), 72 deletions(-) diff --git a/drivers/stemodem/gprs-context.c b/drivers/stemodem/gprs-context.c index 9f59579..4260d31 100644 --- a/drivers/stemodem/gprs-context.c +++ b/drivers/stemodem/gprs-context.c @@ -28,6 +28,7 @@ #include <string.h> #include <stdlib.h> #include <stdio.h> +#include <errno.h> #include <glib.h> @@ -46,10 +47,11 @@ #include "stemodem.h" #include "caif_socket.h" #include "if_caif.h" +#include "caif_rtnl.h" -#define MAX_CAIF_DEVICES 7 +#define MAX_CAIF_DEVICES 4 #define MAX_DNS 2 -#define MAX_ELEM 20 +#define IP_ADDR_LEN 20 #define AUTH_BUF_LENGTH (OFONO_GPRS_MAX_USERNAME_LENGTH + \ OFONO_GPRS_MAX_PASSWORD_LENGTH + 128) @@ -65,21 +67,29 @@ struct gprs_context_data { }; struct conn_info { + /* + * cid is allocated in oFono Core and is identifying + * the Account. cid = 0 indicates that it is currently unused. + */ unsigned int cid; - unsigned int device; + /* Id used by CAIF and EPPSD to identify the CAIF channel*/ unsigned int channel_id; - char interface[10]; + /* Linux Interface Id */ + unsigned int ifindex; + /* Linux Interface name */ + char interface[IF_NAMESIZE]; + gboolean created; }; struct eppsd_response { char *current; - char ip_address[MAX_ELEM]; - char subnet_mask[MAX_ELEM]; - char mtu[MAX_ELEM]; - char default_gateway[MAX_ELEM]; - char dns_server1[MAX_ELEM]; - char dns_server2[MAX_ELEM]; - char p_cscf_server[MAX_ELEM]; + char ip_address[IP_ADDR_LEN]; + char subnet_mask[IP_ADDR_LEN]; + char mtu[IP_ADDR_LEN]; + char default_gateway[IP_ADDR_LEN]; + char dns_server1[IP_ADDR_LEN]; + char dns_server2[IP_ADDR_LEN]; + char p_cscf_server[IP_ADDR_LEN]; }; static void start_element_handler(GMarkupParseContext *context, @@ -122,8 +132,8 @@ static void text_handler(GMarkupParseContext *context, struct eppsd_response *rsp = user_data; if (rsp->current) { - strncpy(rsp->current, text, MAX_ELEM); - rsp->current[MAX_ELEM] = 0; + strncpy(rsp->current, text, IP_ADDR_LEN); + rsp->current[IP_ADDR_LEN] = 0; } } @@ -153,8 +163,7 @@ static gint conn_compare_by_cid(gconstpointer a, gconstpointer b) return 0; } -static struct conn_info *conn_info_create(unsigned int device, - unsigned int channel_id) +static struct conn_info *conn_info_create(unsigned int channel_id) { struct conn_info *connection = g_try_new0(struct conn_info, 1); @@ -162,26 +171,61 @@ static struct conn_info *conn_info_create(unsigned int device, return NULL; connection->cid = 0; - connection->device = device; connection->channel_id = channel_id; return connection; } +static void rtnl_callback(int result, gpointer user_data, + char *ifname, int ifindex) +{ + struct conn_info *conn = user_data; + + strncpy(conn->interface, ifname, sizeof(conn->interface)); + conn->ifindex = ifindex; + + if (result == 0) + conn->created = TRUE; + else { + conn->created = FALSE; + DBG("Could not create CAIF Interface"); + } +} + /* * Creates a new IP interface for CAIF. */ -static gboolean caif_if_create(const char *interface, unsigned int connid) +static gboolean caif_if_create(struct conn_info *conn) { - return FALSE; + int err; + + err = caif_rtnl_create_interface(conn, IFLA_CAIF_IPV4_CONNID, + conn->channel_id, FALSE, rtnl_callback); + if (err < 0) { + DBG("Failed to create IP interface for CAIF"); + return FALSE; + } + + return TRUE; } /* * Removes IP interface for CAIF. */ -static gboolean caif_if_remove(const char *interface, unsigned int connid) +static void caif_if_remove(struct conn_info *conn) { - return FALSE; + if (!conn->created) + return; + + if (caif_rtnl_delete_interface(conn->ifindex) < 0) { + ofono_error("Failed to delete caif interface %s", + conn->interface); + return; + } + + DBG("removed CAIF interface ch:%d ifname:%s ifindex:%d\n", + conn->channel_id, conn->interface, conn->ifindex); + return; } static void ste_eppsd_down_cb(gboolean ok, GAtResult *result, @@ -192,11 +236,14 @@ static void ste_eppsd_down_cb(gboolean ok, GAtResult *result, struct ofono_gprs_context *gc = cbd->user; struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc); struct ofono_error error; - struct conn_info *conn; + struct conn_info *conn = NULL; GSList *l; - if (!ok) - goto error; + if (!ok) { + decode_at_error(&error, g_at_result_final_response(result)); + cb(&error, cbd->data); + return; + } l = g_slist_find_custom(g_caif_devices, GUINT_TO_POINTER(gcd->active_context), @@ -210,16 +257,8 @@ static void ste_eppsd_down_cb(gboolean ok, GAtResult *result, } conn = l->data; - - if (!caif_if_remove(conn->interface, conn->channel_id)) { - DBG("Failed to remove caif interface %s.", - conn->interface); - } - conn->cid = 0; - - decode_at_error(&error, g_at_result_final_response(result)); - cb(&error, cbd->data); + CALLBACK_WITH_SUCCESS(cb, cbd->data); return; error: @@ -237,26 +276,30 @@ static void ste_eppsd_up_cb(gboolean ok, GAtResult *result, gpointer user_data) GSList *l; int i; gsize length; - char *res_string; + const char *res_string; const char *dns[MAX_DNS + 1]; struct eppsd_response rsp; GMarkupParseContext *context = NULL; + struct ofono_error error; l = g_slist_find_custom(g_caif_devices, GUINT_TO_POINTER(gcd->active_context), conn_compare_by_cid); if (!l) { - DBG("Did not find data (device and channel id)" - "for connection with cid; %d", - gcd->active_context); + DBG("CAIF Device gone missing (cid:%d)", gcd->active_context); goto error; } conn = l->data; - if (!ok) - goto error; + if (!ok) { + conn->cid = 0; + gcd->active_context = 0; + decode_at_error(&error, g_at_result_final_response(result)); + cb(&error, NULL, 0, NULL, NULL, NULL, NULL, cbd->data); + return; + } rsp.current = NULL; context = g_markup_parse_context_new(&parser, 0, &rsp, NULL); @@ -266,7 +309,7 @@ static void ste_eppsd_up_cb(gboolean ok, GAtResult *result, gpointer user_data) for (i = 0; i < g_at_result_num_response_lines(result); i++) { g_at_result_iter_next(&iter, NULL); - res_string = strdup(g_at_result_iter_raw_line(&iter)); + res_string = g_at_result_iter_raw_line(&iter); length = strlen(res_string); if (!g_markup_parse_context_parse(context, res_string, @@ -283,20 +326,9 @@ static void ste_eppsd_up_cb(gboolean ok, GAtResult *result, gpointer user_data) dns[1] = rsp.dns_server2; dns[2] = NULL; - sprintf(conn->interface, "caif%u", conn->device); - - if (!caif_if_create(conn->interface, conn->channel_id)) { - ofono_error("Failed to create caif interface %s.", - conn->interface); - CALLBACK_WITH_SUCCESS(cb, NULL, FALSE, rsp.ip_address, + CALLBACK_WITH_SUCCESS(cb, conn->interface, TRUE, rsp.ip_address, rsp.subnet_mask, rsp.default_gateway, dns, cbd->data); - } else { - CALLBACK_WITH_SUCCESS(cb, conn->interface, - FALSE, rsp.ip_address, rsp.subnet_mask, - rsp.default_gateway, dns, cbd->data); - } - return; error: @@ -308,6 +340,7 @@ error: if (conn) conn->cid = 0; + gcd->active_context = 0; CALLBACK_WITH_FAILURE(cb, NULL, 0, NULL, NULL, NULL, NULL, cbd->data); } @@ -319,12 +352,23 @@ static void ste_cgdcont_cb(gboolean ok, GAtResult *result, gpointer user_data) struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc); struct cb_data *ncbd = NULL; char buf[128]; - struct conn_info *conn; + struct conn_info *conn = NULL; GSList *l; + l = g_slist_find_custom(g_caif_devices, + GUINT_TO_POINTER(gcd->active_context), + conn_compare_by_cid); + + if (!l) { + DBG("CAIF Device gone missing (cid:%d)", gcd->active_context); + goto error; + } + + conn = l->data; + if (!ok) { struct ofono_error error; - + conn->cid = 0; gcd->active_context = 0; decode_at_error(&error, g_at_result_final_response(result)); @@ -332,26 +376,18 @@ static void ste_cgdcont_cb(gboolean ok, GAtResult *result, gpointer user_data) return; } - ncbd = g_memdup(cbd, sizeof(struct cb_data)); - - l = g_slist_find_custom(g_caif_devices, GUINT_TO_POINTER(0), - conn_compare_by_cid); - - if (!l) { - DBG("at_cgdcont_cb, no more available devices"); - goto error; - } - - conn = l->data; - conn->cid = gcd->active_context; snprintf(buf, sizeof(buf), "AT*EPPSD=1,%u,%u", conn->channel_id, conn->cid); + ncbd = g_memdup(cbd, sizeof(struct cb_data)); if (g_at_chat_send(gcd->chat, buf, NULL, ste_eppsd_up_cb, ncbd, g_free) > 0) return; error: + if (conn) + conn->cid = 0; + g_free(ncbd); gcd->active_context = 0; @@ -368,6 +404,8 @@ static void ste_gprs_activate_primary(struct ofono_gprs_context *gc, struct cb_data *cbd = cb_data_new(cb, data); char buf[AUTH_BUF_LENGTH]; int len; + GSList *l; + struct conn_info *conn = NULL; if (!cbd) goto error; @@ -375,6 +413,23 @@ static void ste_gprs_activate_primary(struct ofono_gprs_context *gc, gcd->active_context = ctx->cid; cbd->user = gc; + /* Find free connection with cid zero */ + l = g_slist_find_custom(g_caif_devices, GUINT_TO_POINTER(0), + conn_compare_by_cid); + + if (!l) { + DBG("No more available CAIF devices"); + goto error; + } + + conn = l->data; + if (!conn->created) { + DBG("CAIF interface not created (rtnl error?)"); + goto error; + } + + conn->cid = ctx->cid; + len = snprintf(buf, sizeof(buf), "AT+CGDCONT=%u,\"IP\"", ctx->cid); if (ctx->apn) @@ -389,7 +444,7 @@ static void ste_gprs_activate_primary(struct ofono_gprs_context *gc, * Set username and password, this should be done after CGDCONT * or an error can occur. We don't bother with error checking * here - * */ + */ snprintf(buf, sizeof(buf), "AT*EIAAUW=%d,1,\"%s\",\"%s\"", ctx->cid, ctx->username, ctx->password); @@ -398,6 +453,10 @@ static void ste_gprs_activate_primary(struct ofono_gprs_context *gc, return; error: + if (conn) + conn->cid = 0; + + gcd->active_context = 0; g_free(cbd); CALLBACK_WITH_FAILURE(cb, NULL, 0, NULL, NULL, NULL, NULL, data); @@ -423,8 +482,8 @@ static void ste_gprs_deactivate_primary(struct ofono_gprs_context *gc, conn_compare_by_cid); if (!l) { - DBG("at_gprs_deactivate_primary, did not find" - "data (channel id) for connection with cid; %d", id); + DBG("did not find data (channel id) " + "for connection with cid; %d", id); goto error; } @@ -516,9 +575,11 @@ static int ste_gprs_context_probe(struct ofono_gprs_context *gc, ofono_gprs_context_set_data(gc, gcd); for (i = 0; i < MAX_CAIF_DEVICES; i++) { - ci = conn_info_create(i, i+1); - if (ci) - g_caif_devices = g_slist_append(g_caif_devices, ci); + ci = conn_info_create(i+1); + if (!ci) + return -ENOMEM; + caif_if_create(ci); + g_caif_devices = g_slist_append(g_caif_devices, ci); } return 0; @@ -527,7 +588,7 @@ static int ste_gprs_context_probe(struct ofono_gprs_context *gc, static void ste_gprs_context_remove(struct ofono_gprs_context *gc) { struct gprs_context_data *gcd = ofono_gprs_context_get_data(gc); - + g_slist_foreach(g_caif_devices, (GFunc) caif_if_remove, NULL); g_slist_foreach(g_caif_devices, (GFunc) g_free, NULL); g_slist_free(g_caif_devices); g_caif_devices = NULL; @@ -548,10 +609,12 @@ static struct ofono_gprs_context_driver driver = { void ste_gprs_context_init() { + caif_rtnl_init(); ofono_gprs_context_driver_register(&driver); } void ste_gprs_context_exit() { + caif_rtnl_exit(); ofono_gprs_context_driver_unregister(&driver); } -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v3 1/2] stemodem: Add RTNL functionality managing CAIF Network Interfaces. 2010-11-03 18:40 [PATCH v3 1/2] stemodem: Add RTNL functionality managing CAIF Network Interfaces Sjur =?unknown-8bit?q?Br=C3=A6ndeland?= 2010-11-03 18:40 ` [PATCH v3 2/2] stemodem: Update gprs-context to use rtnl to create/remove interfaces Sjur =?unknown-8bit?q?Br=C3=A6ndeland?= @ 2010-11-04 14:02 ` Sjur =?unknown-8bit?q?Br=C3=A6ndeland?= 1 sibling, 0 replies; 3+ messages in thread From: Sjur =?unknown-8bit?q?Br=C3=A6ndeland?= @ 2010-11-04 14:02 UTC (permalink / raw) To: ofono [-- Attachment #1: Type: text/plain, Size: 1408 bytes --] Hi Marcel. > +int caif_rtnl_init(void) > +{ > + struct sockaddr_nl addr; > + int sk, err; > + GError *gerr = NULL; > + > + sk = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); > + if (sk < 0) > + return sk; > + > + memset(&addr, 0, sizeof(addr)); > + addr.nl_family = AF_NETLINK; > + addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE; > + > + err = bind(sk, (struct sockaddr *) &addr, sizeof(addr)); > + if (err < 0) { > + close(sk); > + return err; > + } > + > + channel = g_io_channel_unix_new(sk); > + g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, &gerr); > + g_io_channel_set_encoding(channel, NULL, &gerr); > + g_io_channel_set_buffered(channel, TRUE); > + g_io_channel_set_close_on_unref(channel, TRUE); > + > + rtnl_watch = g_io_add_watch(channel, > + G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR, > + netlink_event, NULL); > + pending_requests = NULL; > + > + return 0; > +} Sigh, I realize I have a potential leak on gerr above. I'll wait for more review comments from you, and resubmit later. Regards, Sjur ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2010-11-04 14:02 UTC | newest] Thread overview: 3+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-11-03 18:40 [PATCH v3 1/2] stemodem: Add RTNL functionality managing CAIF Network Interfaces Sjur =?unknown-8bit?q?Br=C3=A6ndeland?= 2010-11-03 18:40 ` [PATCH v3 2/2] stemodem: Update gprs-context to use rtnl to create/remove interfaces Sjur =?unknown-8bit?q?Br=C3=A6ndeland?= 2010-11-04 14:02 ` [PATCH v3 1/2] stemodem: Add RTNL functionality managing CAIF Network Interfaces Sjur =?unknown-8bit?q?Br=C3=A6ndeland?=
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox