mirror of git://git.sysmocom.de/ofono
Phonet Netlink helpers
Signed-off-by: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
This commit is contained in:
parent
4b9b46d25a
commit
8e79f89046
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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@
|
|
@ -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 <remi.denis-courmont@nokia.com>
|
||||
*
|
||||
* 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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#ifndef SOL_NETLINK
|
||||
#define SOL_NETLINK 270 /* libc!? */
|
||||
#endif
|
||||
#ifndef AF_PHONET
|
||||
#define AF_PHONET 35
|
||||
#endif
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/phonet.h>
|
||||
#include <glib.h>
|
||||
|
||||
#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);
|
||||
}
|
|
@ -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 <remi.denis-courmont@nokia.com>
|
||||
*
|
||||
* 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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
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
|
Loading…
Reference in New Issue