[PATCH 2/4] stemodem: Add RTNL functionality for CAIF Netw Interface.

2010-10-28 Thread Sjur Brændeland
From: Sjur Brændeland 

Add file rtnl.c for creating and deleting CAIF network
interfaces using the RTNL protocol. The interface is
asynchronous.

Only RTNL NEWLINK and DELLINK commands are implemented.
CAIF requires NEWLINK to contain channel-id and ip-type
(ipv4/ipv6) as arguments.

---
 drivers/stemodem/rtnl.c |  365 +++
 1 files changed, 365 insertions(+), 0 deletions(-)
 create mode 100644 drivers/stemodem/rtnl.c

diff --git a/drivers/stemodem/rtnl.c b/drivers/stemodem/rtnl.c
new file mode 100644
index 000..38f7f43
--- /dev/null
+++ b/drivers/stemodem/rtnl.c
@@ -0,0 +1,365 @@
+/*
+ *
+ *  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 
+#endif
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#include 
+
+#include "if_caif.h"
+#include "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;
+   struct rtnl_req_param req;
+   struct rtnl_rsp_param rsp;
+};
+
+static GSList *pending_requests;
+static GIOChannel *channel;
+static guint32 rtnl_seqnr;
+static guint  rtnl_watch;
+
+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->rsp.ifname, ifname,
+   sizeof(req->rsp.ifname));
+   req->rsp.ifname[sizeof(req->rsp.ifname)-1] = '\0';
+   req->rsp.ifindex = index;
+}
+
+static int send_rtnl_req(struct iplink_req *req)
+{
+   struct sockaddr_nl addr;
+   int sk, ret;
+
+   sk = g_io_channel_unix_get_fd(channel);
+
+   memset(&addr, 0, sizeof(addr));
+   addr.nl_family = AF_NETLINK;
+
+   ret = sendto(sk, req, req->n.nlmsg_len, 0,
+   (struct sockaddr *) &addr, sizeof(addr));
+   if (ret < 0)
+   return ret;
+   return 0;
+}
+
+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)
+{
+
+   if (req->req.callback && req->n.nlmsg_type == RTM_NEWLINK)
+   req->req.callback(&req->rsp);
+
+   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);
+   DBG("NEWLINK req:%p\n", req);
+   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);
+

Re: [PATCH 2/4] stemodem: Add RTNL functionality for CAIF Netw Interface.

2010-11-01 Thread Marcel Holtmann
Hi Sjur,

> Add file rtnl.c for creating and deleting CAIF network
> interfaces using the RTNL protocol. The interface is
> asynchronous.
> 
> Only RTNL NEWLINK and DELLINK commands are implemented.
> CAIF requires NEWLINK to contain channel-id and ip-type
> (ipv4/ipv6) as arguments.
> 
> ---
>  drivers/stemodem/rtnl.c |  365 
> +++
>  1 files changed, 365 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/stemodem/rtnl.c

I have no problems with the file names. It does make sense to keep them
simple. However if this is CAIF related, then using caif_rtnl.[ch] might
be a good idea.

And you can combine the patches for the header file, for the actual code
and the Makefile.am into one. That is fine.



And I have not looked through the whole patch yet.

> +int rtnl_init(void)
> +{
> + struct sockaddr_nl addr;
> + int sk, ret;
> +
> + 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;
> +
> + ret = bind(sk, (struct sockaddr *) &addr, sizeof(addr));
> + if (ret < 0) {
> + close(sk);
> + return ret;
> + }
> +
> + channel = g_io_channel_unix_new(sk);
> + 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);
> +
> + return 0;
> +}
> +
> +void rtnl_exit(void)
> +{
> + GSList *list;
> +
> + if (rtnl_watch > 0)
> + g_source_remove(rtnl_watch);
> +
> + for (list = pending_requests; list; list = list->next) {
> + struct iplink_req *req = list->data;
> + g_free(req);
> + list->data = NULL;
> + }
> +
> + g_slist_free(pending_requests);
> + pending_requests = NULL;
> +
> + g_io_channel_shutdown(channel, TRUE, NULL);
> + g_io_channel_unref(channel);
> +
> + channel = NULL;
> +}

Using global function names like rtnl_init and rtnl_exit is not gonna
cut it. This code is CAIF specific and you need at least prefix the
public functions properly.

I am not sure what is best here. Use caif_rtnl_ or ste_rtnl_ or maybe
just skip the keyword rtnl and just prefix it with caif_ only.

Regards

Marcel


___
ofono mailing list
ofono@ofono.org
http://lists.ofono.org/listinfo/ofono