2009-05-06 16:41:57 +00:00
|
|
|
/*
|
|
|
|
* DECT Netlink Interface
|
|
|
|
*
|
2010-03-10 13:17:50 +00:00
|
|
|
* Copyright (c) 2009-2010 Patrick McHardy <kaber@trash.net>
|
2009-05-06 16:41:57 +00:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2010-08-02 17:23:23 +00:00
|
|
|
/**
|
|
|
|
* @defgroup llme Lower Layer Management Entity (LLME)
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
2009-05-06 16:41:57 +00:00
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdarg.h>
|
2009-12-06 13:55:49 +00:00
|
|
|
#include <errno.h>
|
2009-05-06 16:41:57 +00:00
|
|
|
|
|
|
|
#include <netlink/netlink.h>
|
|
|
|
#include <netlink/object.h>
|
|
|
|
#include <netlink/msg.h>
|
|
|
|
#include <netlink/dect/cluster.h>
|
2010-03-10 13:17:50 +00:00
|
|
|
#include <netlink/dect/llme.h>
|
2009-05-06 16:41:57 +00:00
|
|
|
#include <netlink/dect/ari.h>
|
|
|
|
|
|
|
|
#include <libdect.h>
|
|
|
|
#include <netlink.h>
|
|
|
|
#include <utils.h>
|
2010-07-26 20:47:53 +00:00
|
|
|
#include <io.h>
|
2009-05-06 16:41:57 +00:00
|
|
|
|
2010-03-10 13:17:50 +00:00
|
|
|
#define nl_debug_entry(fmt, args...) \
|
2010-05-27 17:18:59 +00:00
|
|
|
dect_debug(DECT_DEBUG_NL, "\nnetlink: " fmt, ## args)
|
2010-03-10 13:17:50 +00:00
|
|
|
#define nl_debug(fmt, args...) \
|
2010-05-27 17:18:59 +00:00
|
|
|
dect_debug(DECT_DEBUG_NL, "netlink: " fmt, ## args)
|
2010-03-10 13:17:50 +00:00
|
|
|
|
|
|
|
struct dect_netlink_handler {
|
|
|
|
struct dect_handle *dh;
|
2010-08-02 17:23:23 +00:00
|
|
|
void (*rcv)(struct dect_handle *, bool,
|
2010-03-10 13:17:50 +00:00
|
|
|
struct nl_object *);
|
2010-08-02 17:23:23 +00:00
|
|
|
bool request;
|
2010-03-10 13:17:50 +00:00
|
|
|
};
|
|
|
|
|
2010-11-14 17:55:10 +00:00
|
|
|
static int dect_netlink_event_rcv(struct nl_msg *msg, void *arg);
|
|
|
|
|
2010-03-10 13:17:50 +00:00
|
|
|
static void __maybe_unused dect_netlink_obj_dump(struct nl_object *obj)
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
char buf[2048];
|
|
|
|
struct nl_dump_params dp = {
|
|
|
|
.dp_type = NL_DUMP_LINE,
|
|
|
|
.dp_buf = buf,
|
|
|
|
.dp_buflen = sizeof(buf),
|
|
|
|
};
|
|
|
|
|
|
|
|
buf[0] = '\0';
|
|
|
|
nl_object_dump(obj, &dp);
|
2010-05-27 17:18:59 +00:00
|
|
|
dect_debug(DECT_DEBUG_NL, "%s", buf);
|
2010-03-10 13:17:50 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dect_netlink_obj_rcv(struct nl_object *obj, void *arg)
|
|
|
|
{
|
|
|
|
struct dect_netlink_handler *handler = arg;
|
|
|
|
|
2010-08-02 17:23:23 +00:00
|
|
|
handler->rcv(handler->dh, handler->request, obj);
|
2010-03-10 13:17:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int dect_netlink_msg_rcv(struct nl_msg *msg, void *arg)
|
|
|
|
{
|
|
|
|
if (nl_msg_parse(msg, dect_netlink_obj_rcv, arg) < 0)
|
|
|
|
nl_debug("message parsing failed type %u\n",
|
|
|
|
nlmsg_hdr(msg)->nlmsg_type);
|
|
|
|
|
|
|
|
return NL_OK;
|
|
|
|
}
|
|
|
|
|
2009-05-06 16:41:57 +00:00
|
|
|
static void dect_netlink_event(struct dect_handle *dh, struct dect_fd *fd,
|
|
|
|
uint32_t event)
|
|
|
|
{
|
2010-03-10 13:17:50 +00:00
|
|
|
if (nl_recvmsgs_default(dh->nlsock) < 0)
|
|
|
|
nl_debug("nl_recvmsgs: %s\n", strerror(errno));
|
2009-05-06 16:41:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void dect_netlink_set_callback(struct dect_handle *dh,
|
|
|
|
nl_recvmsg_msg_cb_t func,
|
|
|
|
void *arg)
|
|
|
|
{
|
|
|
|
nl_socket_modify_cb(dh->nlsock, NL_CB_VALID, NL_CB_CUSTOM, func, arg);
|
|
|
|
}
|
|
|
|
|
2010-03-10 13:17:50 +00:00
|
|
|
/*
|
|
|
|
* Cluster
|
|
|
|
*/
|
|
|
|
|
2009-05-06 16:41:57 +00:00
|
|
|
static void dect_netlink_parse_ari(struct dect_ari *ari, const struct nl_dect_ari *nlari)
|
|
|
|
{
|
|
|
|
ari->arc = nl_dect_ari_get_class(nlari);
|
|
|
|
switch (ari->arc) {
|
|
|
|
case DECT_ARC_A:
|
|
|
|
ari->emc = nl_dect_ari_get_emc(nlari);
|
|
|
|
ari->fpn = nl_dect_ari_get_fpn(nlari);
|
|
|
|
break;
|
|
|
|
case DECT_ARC_B:
|
|
|
|
ari->eic = nl_dect_ari_get_eic(nlari);
|
|
|
|
ari->fpn = nl_dect_ari_get_fpn(nlari);
|
|
|
|
ari->fps = nl_dect_ari_get_fps(nlari);
|
|
|
|
break;
|
|
|
|
case DECT_ARC_C:
|
|
|
|
ari->poc = nl_dect_ari_get_poc(nlari);
|
|
|
|
ari->fpn = nl_dect_ari_get_fpn(nlari);
|
|
|
|
ari->fps = nl_dect_ari_get_fps(nlari);
|
|
|
|
break;
|
|
|
|
case DECT_ARC_D:
|
|
|
|
ari->gop = nl_dect_ari_get_gop(nlari);
|
|
|
|
ari->fpn = nl_dect_ari_get_fpn(nlari);
|
|
|
|
break;
|
|
|
|
case DECT_ARC_E:
|
|
|
|
ari->fil = nl_dect_ari_get_fil(nlari);
|
|
|
|
ari->fpn = nl_dect_ari_get_fpn(nlari);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-14 17:53:02 +00:00
|
|
|
static void dect_netlink_build_ari(struct nl_dect_ari *nlari, const struct dect_ari *ari)
|
|
|
|
{
|
|
|
|
nl_dect_ari_set_class(nlari, ari->arc);
|
|
|
|
switch (ari->arc) {
|
|
|
|
case DECT_ARC_A:
|
|
|
|
nl_dect_ari_set_emc(nlari, ari->emc);
|
|
|
|
nl_dect_ari_set_fpn(nlari, ari->fpn);
|
|
|
|
break;
|
|
|
|
case DECT_ARC_B:
|
|
|
|
nl_dect_ari_set_eic(nlari, ari->eic);
|
|
|
|
nl_dect_ari_set_fpn(nlari, ari->fpn);
|
|
|
|
nl_dect_ari_set_fps(nlari, ari->fps);
|
|
|
|
break;
|
|
|
|
case DECT_ARC_C:
|
|
|
|
nl_dect_ari_set_poc(nlari, ari->poc);
|
|
|
|
nl_dect_ari_set_fpn(nlari, ari->fpn);
|
|
|
|
nl_dect_ari_set_fps(nlari, ari->fps);
|
|
|
|
break;
|
|
|
|
case DECT_ARC_D:
|
|
|
|
nl_dect_ari_set_gop(nlari, ari->gop);
|
|
|
|
nl_dect_ari_set_fpn(nlari, ari->fpn);
|
|
|
|
break;
|
|
|
|
case DECT_ARC_E:
|
|
|
|
nl_dect_ari_set_fil(nlari, ari->fil);
|
|
|
|
nl_dect_ari_set_fpn(nlari, ari->fpn);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-02 17:23:23 +00:00
|
|
|
static void dect_netlink_cluster_rcv(struct dect_handle *dh, bool request,
|
|
|
|
struct nl_object *obj)
|
2009-05-06 16:41:57 +00:00
|
|
|
{
|
2010-03-10 13:17:50 +00:00
|
|
|
struct nl_dect_cluster *cl = nl_object_priv(obj);
|
2009-05-06 16:41:57 +00:00
|
|
|
|
|
|
|
dh->index = nl_dect_cluster_get_index(cl);
|
|
|
|
dh->mode = nl_dect_cluster_get_mode(cl);
|
|
|
|
dect_netlink_parse_ari(&dh->pari, nl_dect_cluster_get_pari(cl));
|
2010-03-10 13:17:50 +00:00
|
|
|
|
|
|
|
nl_debug("%s: mode %s ARI: class A: EMC: %.4x FPN: %.5x\n",
|
|
|
|
nl_dect_cluster_get_name(cl),
|
|
|
|
dh->mode == DECT_MODE_FP ? "FP" : "PP",
|
|
|
|
dh->pari.emc, dh->pari.fpn);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dect_netlink_get_cluster(struct dect_handle *dh, const char *name)
|
|
|
|
{
|
|
|
|
struct dect_netlink_handler handler = {
|
|
|
|
.dh = dh,
|
|
|
|
.rcv = dect_netlink_cluster_rcv,
|
|
|
|
};
|
|
|
|
struct nl_dect_cluster *cl;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
cl = nl_dect_cluster_alloc();
|
|
|
|
if (cl == NULL)
|
|
|
|
return -1;
|
|
|
|
nl_dect_cluster_set_name(cl, name);
|
|
|
|
|
|
|
|
dect_netlink_set_callback(dh, dect_netlink_msg_rcv, &handler);
|
|
|
|
err = nl_dect_cluster_query(dh->nlsock, cl, 0);
|
2010-11-14 17:55:10 +00:00
|
|
|
dect_netlink_set_callback(dh, dect_netlink_event_rcv, dh);
|
2010-03-10 13:17:50 +00:00
|
|
|
nl_dect_cluster_put(cl);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* LLME
|
|
|
|
*/
|
|
|
|
|
2010-08-04 01:48:11 +00:00
|
|
|
static struct nl_dect_llme_msg *dect_llme_msg_init(const struct dect_handle *dh,
|
2010-11-14 17:53:02 +00:00
|
|
|
enum dect_llme_msg_types type,
|
|
|
|
enum dect_llme_ops op)
|
2010-08-04 01:48:11 +00:00
|
|
|
{
|
|
|
|
struct nl_dect_llme_msg *lmsg;
|
|
|
|
|
|
|
|
lmsg = nl_dect_llme_msg_alloc();
|
|
|
|
if (lmsg == NULL)
|
|
|
|
return NULL;
|
|
|
|
nl_dect_llme_msg_set_type(lmsg, type);
|
2010-11-14 17:53:02 +00:00
|
|
|
nl_dect_llme_msg_set_op(lmsg, op);
|
2010-08-04 01:48:11 +00:00
|
|
|
nl_dect_llme_msg_set_index(lmsg, dh->index);
|
|
|
|
return lmsg;
|
|
|
|
}
|
|
|
|
|
2010-08-02 17:23:23 +00:00
|
|
|
/**
|
|
|
|
* Get FP capabilities
|
|
|
|
*
|
|
|
|
* @param dh libdect DECT handle
|
|
|
|
*/
|
|
|
|
const struct dect_fp_capabilities *dect_llme_fp_capabilities(const struct dect_handle *dh)
|
|
|
|
{
|
|
|
|
return &dh->fpc;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(dect_llme_fp_capabilities);
|
|
|
|
|
2010-08-04 01:48:11 +00:00
|
|
|
static void dect_fp_capabilities_dump(const struct dect_fp_capabilities *fpc)
|
2010-03-10 13:17:50 +00:00
|
|
|
{
|
2010-08-04 18:59:17 +00:00
|
|
|
char buf1[512], buf2[512], buf3[512];
|
2010-03-10 13:17:50 +00:00
|
|
|
|
|
|
|
nl_dect_llme_fpc2str(fpc->fpc, buf1, sizeof(buf1));
|
|
|
|
nl_dect_llme_efpc2str(fpc->efpc, buf2, sizeof(buf2));
|
|
|
|
nl_dect_llme_efpc22str(fpc->efpc2, buf3, sizeof(buf3));
|
2010-08-04 01:48:11 +00:00
|
|
|
if (buf1[0] || buf2[0] || buf3[0])
|
|
|
|
nl_debug("FPC: %s%s%s%s%s\n",
|
|
|
|
buf1, buf1[0] && (buf2[0] || buf3[0]) ? "," : "",
|
|
|
|
buf2, buf2[0] && buf3[0] ? "," : "", buf3);
|
2010-03-10 13:17:50 +00:00
|
|
|
|
|
|
|
nl_dect_llme_hlc2str(fpc->hlc, buf1, sizeof(buf1));
|
|
|
|
nl_dect_llme_ehlc2str(fpc->ehlc, buf2, sizeof(buf2));
|
|
|
|
nl_dect_llme_ehlc22str(fpc->ehlc2, buf3, sizeof(buf3));
|
2010-08-04 01:48:11 +00:00
|
|
|
if (buf1[0] || buf2[0] || buf3[0])
|
|
|
|
nl_debug("HLC: %s%s%s%s%s\n",
|
|
|
|
buf1, buf1[0] && (buf2[0] || buf3[0]) ? "," : "",
|
|
|
|
buf2, buf2[0] && buf3[0] ? "," : "", buf3);
|
2010-03-10 13:17:50 +00:00
|
|
|
}
|
|
|
|
|
2010-08-02 17:23:23 +00:00
|
|
|
static void dect_netlink_llme_mac_info_rcv(struct dect_handle *dh, bool request,
|
2010-03-10 13:17:50 +00:00
|
|
|
struct nl_dect_llme_msg *lmsg)
|
|
|
|
{
|
|
|
|
struct dect_fp_capabilities *fpc = &dh->fpc;
|
2010-11-14 17:53:02 +00:00
|
|
|
struct dect_ari *pari = NULL, _pari;
|
|
|
|
|
|
|
|
if (nl_dect_llme_mac_info_test_pari(lmsg)) {
|
|
|
|
dect_netlink_parse_ari(&_pari, nl_dect_llme_mac_info_get_pari(lmsg));
|
|
|
|
pari = &_pari;
|
|
|
|
}
|
2010-03-10 13:17:50 +00:00
|
|
|
|
|
|
|
fpc->fpc = nl_dect_llme_mac_info_get_fpc(lmsg);
|
|
|
|
fpc->hlc = nl_dect_llme_mac_info_get_hlc(lmsg);
|
|
|
|
fpc->efpc = nl_dect_llme_mac_info_get_efpc(lmsg);
|
|
|
|
fpc->ehlc = nl_dect_llme_mac_info_get_ehlc(lmsg);
|
|
|
|
fpc->efpc2 = nl_dect_llme_mac_info_get_efpc2(lmsg);
|
|
|
|
fpc->ehlc2 = nl_dect_llme_mac_info_get_ehlc2(lmsg);
|
|
|
|
|
|
|
|
dect_fp_capabilities_dump(fpc);
|
2010-08-02 17:23:23 +00:00
|
|
|
if (!request)
|
2010-11-14 17:53:02 +00:00
|
|
|
dh->ops->llme_ops->mac_me_info_ind(dh, pari, fpc);
|
2009-05-06 16:41:57 +00:00
|
|
|
}
|
|
|
|
|
2010-08-02 17:23:23 +00:00
|
|
|
static void dect_netlink_llme_rcv(struct dect_handle *dh, bool request,
|
|
|
|
struct nl_object *obj)
|
2009-05-06 16:41:57 +00:00
|
|
|
{
|
2010-03-10 13:17:50 +00:00
|
|
|
struct nl_dect_llme_msg *lmsg = nl_object_priv(obj);
|
|
|
|
enum dect_llme_msg_types type;
|
|
|
|
enum dect_llme_ops op;
|
|
|
|
|
|
|
|
type = nl_dect_llme_msg_get_type(lmsg);
|
|
|
|
op = nl_dect_llme_msg_get_op(lmsg);
|
|
|
|
|
|
|
|
#define LLME_MSG(type, op) (type << 16 | op)
|
|
|
|
switch (LLME_MSG(type, op)) {
|
|
|
|
case LLME_MSG(DECT_LLME_MAC_INFO, DECT_LLME_INDICATE):
|
2010-08-02 17:23:23 +00:00
|
|
|
return dect_netlink_llme_mac_info_rcv(dh, request, lmsg);
|
2010-03-10 13:17:50 +00:00
|
|
|
default:
|
|
|
|
nl_debug("unknown LLME message: type: %u op: %u\n", type, op);
|
|
|
|
dect_netlink_obj_dump(obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-05 08:26:10 +00:00
|
|
|
/**
|
|
|
|
* MAC_ME_RFP_PRELOAD-req primitive
|
|
|
|
*
|
|
|
|
* @param dh libdect DECT handle
|
|
|
|
* @param fpc Fixed Part Capabilities
|
|
|
|
*
|
|
|
|
* Issue a MAC_ME_RFP_PRELOAD-req request to the kernel. If successful the
|
|
|
|
* broadcasted fixed part capabilities will be changed to the supplied values.
|
|
|
|
*
|
|
|
|
* @sa ETSI EN 300 175-3, section 8.3.2.1.
|
|
|
|
*/
|
2010-08-04 01:48:11 +00:00
|
|
|
int dect_llme_rfp_preload_req(struct dect_handle *dh,
|
|
|
|
const struct dect_fp_capabilities *fpc)
|
|
|
|
{
|
|
|
|
struct dect_netlink_handler handler = {
|
|
|
|
.dh = dh,
|
|
|
|
.rcv = dect_netlink_llme_rcv,
|
|
|
|
.request = true,
|
|
|
|
};
|
|
|
|
struct nl_dect_llme_msg *lmsg;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
nl_debug_entry("MAC_ME_RFP_PRELOAD-req\n");
|
|
|
|
dect_fp_capabilities_dump(fpc);
|
|
|
|
|
2010-11-14 17:53:02 +00:00
|
|
|
lmsg = dect_llme_msg_init(dh, DECT_LLME_MAC_RFP_PRELOAD, DECT_LLME_REQUEST);
|
2010-08-04 01:48:11 +00:00
|
|
|
if (lmsg == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
nl_dect_llme_mac_info_set_hlc(lmsg, fpc->hlc);
|
|
|
|
nl_dect_llme_mac_info_set_ehlc(lmsg, fpc->ehlc);
|
|
|
|
nl_dect_llme_mac_info_set_ehlc2(lmsg, fpc->ehlc2);
|
|
|
|
|
|
|
|
dect_netlink_set_callback(dh, dect_netlink_msg_rcv, &handler);
|
|
|
|
err = nl_dect_llme_request(dh->nlsock, lmsg);
|
2010-11-14 17:55:10 +00:00
|
|
|
dect_netlink_set_callback(dh, dect_netlink_event_rcv, dh);
|
2010-08-04 01:48:11 +00:00
|
|
|
nl_dect_llme_msg_put(lmsg);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(dect_llme_rfp_preload_req);
|
|
|
|
|
2010-11-14 17:53:02 +00:00
|
|
|
/**
|
|
|
|
* MAC_ME_INFO-res primitive
|
|
|
|
*
|
|
|
|
* @param dh libdect DECT handle
|
|
|
|
* @param pari Primary Access Rights Identity of FP to lock to
|
|
|
|
*
|
|
|
|
* Issue a MAC_ME_INFO-res primitive to the kernel. The kernel will attempt
|
|
|
|
* to lock to the FP identified by the given PARI.
|
|
|
|
*
|
|
|
|
* @sa ETSI EN 300 175-3, section 8.3.2.3.
|
|
|
|
*/
|
|
|
|
int dect_llme_mac_me_info_res(struct dect_handle *dh, const struct dect_ari *pari)
|
|
|
|
{
|
|
|
|
struct nl_dect_llme_msg *lmsg;
|
|
|
|
struct nl_dect_ari *nlari;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
nl_debug_entry("MAC_ME_INFO-res\n");
|
|
|
|
lmsg = dect_llme_msg_init(dh, DECT_LLME_MAC_INFO, DECT_LLME_RESPONSE);
|
|
|
|
if (lmsg == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
nlari = (void *)nl_dect_llme_mac_info_get_pari(lmsg);
|
|
|
|
dect_netlink_build_ari(nlari, pari);
|
|
|
|
nl_dect_llme_mac_info_set_pari(lmsg, nlari);
|
|
|
|
|
|
|
|
err = nl_dect_llme_respond(dh->nlsock, lmsg);
|
|
|
|
nl_dect_llme_msg_put(lmsg);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(dect_llme_mac_me_info_res);
|
|
|
|
|
|
|
|
static int dect_netlink_mac_me_info_req(struct dect_handle *dh)
|
2010-03-10 13:17:50 +00:00
|
|
|
{
|
|
|
|
struct dect_netlink_handler handler = {
|
2010-08-02 17:23:23 +00:00
|
|
|
.dh = dh,
|
|
|
|
.rcv = dect_netlink_llme_rcv,
|
|
|
|
.request = true,
|
2010-03-10 13:17:50 +00:00
|
|
|
};
|
|
|
|
struct nl_dect_llme_msg *lmsg;
|
|
|
|
int err;
|
|
|
|
|
2010-11-14 17:53:02 +00:00
|
|
|
nl_debug_entry("MAC_ME_INFO-req\n");
|
|
|
|
lmsg = dect_llme_msg_init(dh, DECT_LLME_MAC_INFO, DECT_LLME_REQUEST);
|
2010-03-10 13:17:50 +00:00
|
|
|
if (lmsg == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
dect_netlink_set_callback(dh, dect_netlink_msg_rcv, &handler);
|
|
|
|
err = nl_dect_llme_request(dh->nlsock, lmsg);
|
2010-11-14 17:55:10 +00:00
|
|
|
dect_netlink_set_callback(dh, dect_netlink_event_rcv, dh);
|
2010-03-10 13:17:50 +00:00
|
|
|
nl_dect_llme_msg_put(lmsg);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2010-11-14 17:53:02 +00:00
|
|
|
int dect_llme_scan_req(struct dect_handle *dh)
|
|
|
|
{
|
|
|
|
struct nl_dect_llme_msg *lmsg;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
nl_debug_entry("SCAN-req\n");
|
|
|
|
lmsg = dect_llme_msg_init(dh, DECT_LLME_SCAN, DECT_LLME_REQUEST);
|
|
|
|
if (lmsg == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
err = nl_dect_llme_request(dh->nlsock, lmsg);
|
|
|
|
nl_dect_llme_msg_put(lmsg);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(dect_llme_scan_req);
|
|
|
|
|
2010-03-10 13:17:50 +00:00
|
|
|
static int dect_netlink_event_rcv(struct nl_msg *msg, void *arg)
|
|
|
|
{
|
|
|
|
struct sockaddr_nl *addr = nlmsg_get_src(msg);
|
|
|
|
struct dectmsg *dm = nlmsg_data(nlmsg_hdr(msg));
|
|
|
|
struct dect_handle *dh = arg;
|
|
|
|
struct dect_netlink_handler handler = { .dh = dh };
|
|
|
|
unsigned int group = ffs(addr->nl_groups);
|
|
|
|
|
|
|
|
if (dm->dm_index != dh->index)
|
|
|
|
return NL_OK;
|
|
|
|
|
|
|
|
nl_debug_entry("message group: %u\n", group);
|
|
|
|
switch (group) {
|
|
|
|
case DECTNLGRP_CLUSTER:
|
|
|
|
handler.rcv = dect_netlink_cluster_rcv;
|
|
|
|
break;
|
|
|
|
case DECTNLGRP_LLME:
|
|
|
|
handler.rcv = dect_netlink_llme_rcv;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
nl_debug("unknown message source\n");
|
|
|
|
return NL_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return dect_netlink_msg_rcv(msg, &handler);
|
2009-05-06 16:41:57 +00:00
|
|
|
}
|
|
|
|
|
2010-03-03 13:03:41 +00:00
|
|
|
int dect_netlink_init(struct dect_handle *dh, const char *cluster)
|
2009-05-06 16:41:57 +00:00
|
|
|
{
|
2009-12-06 13:55:49 +00:00
|
|
|
int err = 0;
|
2009-05-06 16:41:57 +00:00
|
|
|
|
|
|
|
dh->nlsock = nl_socket_alloc();
|
|
|
|
if (dh->nlsock == NULL)
|
|
|
|
goto err1;
|
|
|
|
|
|
|
|
err = nl_connect(dh->nlsock, NETLINK_DECT);
|
|
|
|
if (err < 0)
|
|
|
|
goto err2;
|
|
|
|
|
|
|
|
err = nl_socket_set_nonblocking(dh->nlsock);
|
|
|
|
if (err < 0)
|
|
|
|
goto err2;
|
|
|
|
|
2010-08-02 03:25:03 +00:00
|
|
|
dh->nlfd = dect_fd_alloc(dh);
|
2009-05-06 16:41:57 +00:00
|
|
|
if (dh->nlfd == NULL)
|
|
|
|
goto err2;
|
|
|
|
dh->nlfd->fd = nl_socket_get_fd(dh->nlsock);
|
|
|
|
|
2010-08-02 03:25:03 +00:00
|
|
|
dect_fd_setup(dh->nlfd, dect_netlink_event, NULL);
|
|
|
|
if (dect_fd_register(dh, dh->nlfd, DECT_FD_READ))
|
2009-05-06 16:41:57 +00:00
|
|
|
goto err3;
|
|
|
|
|
2010-03-03 13:03:41 +00:00
|
|
|
err = dect_netlink_get_cluster(dh, cluster);
|
2009-05-06 16:41:57 +00:00
|
|
|
if (err < 0)
|
2009-11-13 07:39:33 +00:00
|
|
|
goto err4;
|
2009-05-06 16:41:57 +00:00
|
|
|
|
2010-03-10 13:17:50 +00:00
|
|
|
if (dh->mode == DECT_MODE_PP) {
|
2010-11-14 17:53:02 +00:00
|
|
|
err = dect_netlink_mac_me_info_req(dh);
|
2010-03-10 13:17:50 +00:00
|
|
|
if (err < 0)
|
|
|
|
goto err4;
|
|
|
|
}
|
|
|
|
|
|
|
|
dect_netlink_set_callback(dh, dect_netlink_event_rcv, dh);
|
|
|
|
nl_socket_disable_seq_check(dh->nlsock);
|
|
|
|
nl_socket_add_membership(dh->nlsock, DECTNLGRP_CLUSTER);
|
|
|
|
nl_socket_add_membership(dh->nlsock, DECTNLGRP_LLME);
|
2009-05-06 16:41:57 +00:00
|
|
|
return 0;
|
2010-03-10 13:17:50 +00:00
|
|
|
|
2009-05-06 16:41:57 +00:00
|
|
|
err4:
|
2010-08-02 03:25:03 +00:00
|
|
|
dect_fd_unregister(dh, dh->nlfd);
|
2009-05-06 16:41:57 +00:00
|
|
|
err3:
|
|
|
|
dect_free(dh, dh->nlfd);
|
|
|
|
err2:
|
|
|
|
nl_close(dh->nlsock);
|
2009-11-13 07:39:33 +00:00
|
|
|
nl_socket_free(dh->nlsock);
|
2009-05-06 16:41:57 +00:00
|
|
|
err1:
|
2010-05-27 17:18:59 +00:00
|
|
|
dect_debug(DECT_DEBUG_NL, "dect_netlink_init: %s\n",
|
|
|
|
err == 0 ? strerror(errno) : nl_geterror(err));
|
2009-05-06 16:41:57 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dect_netlink_exit(struct dect_handle *dh)
|
|
|
|
{
|
2010-08-02 03:25:03 +00:00
|
|
|
dect_fd_unregister(dh, dh->nlfd);
|
2009-05-06 16:41:57 +00:00
|
|
|
nl_close(dh->nlsock);
|
2009-11-13 07:39:33 +00:00
|
|
|
nl_socket_free(dh->nlsock);
|
2009-05-06 16:41:57 +00:00
|
|
|
dect_free(dh, dh->nlfd);
|
|
|
|
}
|
2010-08-02 17:23:23 +00:00
|
|
|
|
|
|
|
/** @} */
|