stemodem: Add RTNL functionality managing CAIF Network Interfaces.
PATCH v3 1/2 stemodem: Add RTNL functionality managing CAIF Network Interfaces.
From: Sjur Brændeland <[email protected]>
---
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
Makefile.am +2 -0
@@ -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
drivers/stemodem/caif_rtnl.c new file +382 -0
382 lines not on this page · raw message
drivers/stemodem/caif_rtnl.h new file +29 -0
@@ -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 );
Signature · 1 line
1.6.3.3
PATCH v3 2/2 stemodem: Update gprs-context to use rtnl to create/remove interfaces.
From: Sjur Brændeland <[email protected]>
--- drivers/stemodem/gprs-context.c | 207 +++++++++++++++++++++++++-------------- 1 files changed, 135 insertions(+), 72 deletions(-)
drivers/stemodem/gprs-context.c +135 -72
@@ -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); }
Signature · 1 line
1.6.3.3
Hi Marcel.
Quoted 23 lines
drivers/stemodem/caif_rtnl.c new file +23
-0+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);
drivers/stemodem/caif_rtnl.c line 318
Quoted 10 lines
drivers/stemodem/caif_rtnl.c new file +10
-0+ 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