From 8e79f89046fbe91187b153b2eab689eaaa27cc3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Thu, 4 Jun 2009 18:46:48 +0300 Subject: [PATCH] Phonet Netlink helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Denis-Courmont --- Makefile.am | 2 +- configure.ac | 2 +- isi/Makefile.am | 8 ++ isi/netlink.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++++ isi/netlink.h | 34 +++++++++ 5 files changed, 241 insertions(+), 2 deletions(-) create mode 100644 isi/Makefile.am create mode 100644 isi/netlink.c create mode 100644 isi/netlink.h diff --git a/Makefile.am b/Makefile.am index 2bcf878d..8b63f166 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,5 @@ -SUBDIRS = gdbus gatchat include plugins drivers unit src doc +SUBDIRS = gdbus gatchat isi include plugins drivers unit src doc DISTCHECK_CONFIGURE_FLAGS = --disable-datafiles diff --git a/configure.ac b/configure.ac index 5c5d5605..720e8226 100644 --- a/configure.ac +++ b/configure.ac @@ -86,7 +86,7 @@ AM_CONDITIONAL(DATAFILES, test "${enable_datafiles}" != "no") COMPILER_FLAGS -AC_OUTPUT(Makefile gdbus/Makefile gatchat/Makefile +AC_OUTPUT(Makefile gdbus/Makefile gatchat/Makefile isi/Makefile include/Makefile include/version.h src/Makefile plugins/Makefile drivers/Makefile unit/Makefile doc/Makefile) diff --git a/isi/Makefile.am b/isi/Makefile.am new file mode 100644 index 00000000..e5e85961 --- /dev/null +++ b/isi/Makefile.am @@ -0,0 +1,8 @@ +AM_CFLAGS = @GLIB_CFLAGS@ + +noinst_LTLIBRARIES = libgisi.la +MAINTAINERCLEANFILES = Makefile.in + +libgisi_la_SOURCES = \ + netlink.h netlink.c +libgisi_la_LIBADD = @GLIB_LIBS@ diff --git a/isi/netlink.c b/isi/netlink.c new file mode 100644 index 00000000..3bb61db6 --- /dev/null +++ b/isi/netlink.c @@ -0,0 +1,197 @@ +/* + * This file is part of oFono - Open Source Telephony + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: Rémi Denis-Courmont + * + * 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 +#ifndef SOL_NETLINK +#define SOL_NETLINK 270 /* libc!? */ +#endif +#ifndef AF_PHONET +#define AF_PHONET 35 +#endif +#include +#include +#include + +#include "netlink.h" + +struct pn_netlink { + pn_netlink_cb_t callback; + void *opaque; + guint watch; +}; + +/* Parser Netlink messages */ +static gboolean pn_nl_process(GIOChannel *channel, GIOCondition cond, + gpointer data) +{ + struct { + struct nlmsghdr nlh; + struct rtmsg rtm; + char buf[1024]; + } req; + struct iovec iov = { &req, sizeof(req), }; + struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1, }; + ssize_t ret; + struct nlmsghdr *nlh; + int fd = g_io_channel_unix_get_fd(channel); + struct pn_netlink *self = data; + + if (cond & (G_IO_NVAL|G_IO_HUP)) + return FALSE; + + ret = recvmsg(fd, &msg, 0); + if (ret == -1 || (msg.msg_flags & MSG_TRUNC)) + return TRUE; + + for (nlh = (struct nlmsghdr *)&req; NLMSG_OK(nlh, (size_t)ret); + nlh = NLMSG_NEXT(nlh, ret)) { + const struct ifaddrmsg *ifa; + const struct rtattr *rta; + int len; + bool up; + uint8_t addr = 0; + + if (nlh->nlmsg_type == NLMSG_DONE) + break; + switch (nlh->nlmsg_type) { + case NLMSG_ERROR: { + const struct nlmsgerr *err; + err = (struct nlmsgerr *)NLMSG_DATA(nlh); + g_critical("Netlink error: %s", strerror(-err->error)); + return FALSE; + } + case RTM_NEWADDR: + up = true; + break; + case RTM_DELADDR: + up = false; + break; + default: + continue; + } + /* We have a route message */ + ifa = NLMSG_DATA(nlh); + len = RTM_PAYLOAD(nlh); + + /* If Phonet is absent, kernel transmits other families... */ + if (ifa->ifa_family != AF_PHONET) + continue; + for (rta = IFA_RTA(ifa); RTA_OK(rta, len); + rta = RTA_NEXT(rta, len)) + if (rta->rta_type == IFA_LOCAL) + memcpy(&addr, RTA_DATA(rta), 1); + self->callback(up, addr, ifa->ifa_index, self->opaque); + } + return TRUE; +} + +/* Dump current Phonet address table */ +static int pn_netlink_query(int fd) +{ + struct { + struct nlmsghdr nlh; + struct rtmsg rtm; + } req; + struct sockaddr_nl addr = { .nl_family = AF_NETLINK, }; + + req.nlh.nlmsg_type = RTM_GETADDR; + req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(req.rtm)); + req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; + req.nlh.nlmsg_seq = 0; + req.nlh.nlmsg_pid = getpid(); + + req.rtm.rtm_family = AF_PHONET; + req.rtm.rtm_dst_len = 6; + req.rtm.rtm_src_len = 0; + req.rtm.rtm_tos = 0; + + req.rtm.rtm_table = RT_TABLE_MAIN; + req.rtm.rtm_protocol = RTPROT_STATIC; + req.rtm.rtm_scope = RT_SCOPE_UNIVERSE; + req.rtm.rtm_type = RTN_UNICAST; + req.rtm.rtm_flags = 0; + + if (sendto(fd, &req, req.nlh.nlmsg_len, 0, + (struct sockaddr *)&addr, sizeof(addr)) == -1) + return -1; + return 0; +} + +struct pn_netlink *pn_netlink_start(pn_netlink_cb_t cb, void *opaque) +{ + GIOChannel *chan; + struct pn_netlink *self; + unsigned group = RTNLGRP_PHONET_IFADDR; + int fd; + + self = malloc(sizeof(*self)); + if (self == NULL) + return NULL; + + fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); + if (fd == -1) + goto error; + + fcntl(fd, F_SETFL, O_NONBLOCK | fcntl(fd, F_GETFL)); + if (setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, + &group, sizeof(group))) + goto error; + pn_netlink_query(fd); + + chan = g_io_channel_unix_new(fd); + if (chan == NULL) + goto error; + g_io_channel_set_close_on_unref(chan, TRUE); + g_io_channel_set_encoding(chan, NULL, NULL); + g_io_channel_set_buffered(chan, FALSE); + + self->callback = cb; + self->opaque = opaque; + self->watch = g_io_add_watch(chan, G_IO_IN|G_IO_ERR|G_IO_HUP, + pn_nl_process, self); + g_io_channel_unref(chan); + return 0; + +error: + if (fd != -1) + close(fd); + free(self); + return NULL; +} + +void pn_netlink_stop(struct pn_netlink *self) +{ + g_source_remove(self->watch); + g_free(self); +} diff --git a/isi/netlink.h b/isi/netlink.h new file mode 100644 index 00000000..d34c5e8c --- /dev/null +++ b/isi/netlink.h @@ -0,0 +1,34 @@ +/* + * This file is part of oFono - Open Source Telephony + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: Rémi Denis-Courmont + * + * 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 + * + */ + +#ifndef OFONO_PHONET_NETLINK_H +#define OFONO_PHONET_NETLINK_H 1 +#include +#include + +struct pn_netlink; +typedef void (*pn_netlink_cb_t)(bool, uint8_t, unsigned, void *); + +struct pn_netlink *pn_netlink_start(pn_netlink_cb_t, void *); +void pn_netlink_stop(struct pn_netlink *self); +#endif