Blame src/core/platform/wpan/nm-wpan-utils.c

Packit Service 5ffa24
/* SPDX-License-Identifier: GPL-2.0-or-later */
Packit Service 5ffa24
/*
Packit Service 5ffa24
 * Copyright (C) 2018 Red Hat, Inc.
Packit Service 5ffa24
 */
Packit Service 5ffa24
Packit Service 2bceb2
#include "src/core/nm-default-daemon.h"
Packit Service 5ffa24
Packit Service 5ffa24
#include "nm-wpan-utils.h"
Packit Service 5ffa24
Packit Service 5ffa24
#include <linux/if.h>
Packit Service 5ffa24
Packit Service 5ffa24
#include "nm-platform/nm-netlink.h"
Packit Service 5ffa24
#include "platform/linux/nl802154.h"
Packit Service 5ffa24
#include "nm-platform/nm-platform-utils.h"
Packit Service 5ffa24
Packit Service 5ffa24
#define _NMLOG_PREFIX_NAME "wpan-nl802154"
Packit Service 5ffa24
#define _NMLOG(level, domain, ...)                                                                \
Packit Service 5ffa24
    G_STMT_START                                                                                  \
Packit Service 5ffa24
    {                                                                                             \
Packit Service 5ffa24
        char        _ifname_buf[IFNAMSIZ];                                                        \
Packit Service 5ffa24
        const char *_ifname = self ? nmp_utils_if_indextoname(self->ifindex, _ifname_buf) : NULL; \
Packit Service 5ffa24
                                                                                                  \
Packit Service 5ffa24
        nm_log((level),                                                                           \
Packit Service 5ffa24
               (domain),                                                                          \
Packit Service 5ffa24
               _ifname ?: NULL,                                                                   \
Packit Service 5ffa24
               NULL,                                                                              \
Packit Service 5ffa24
               "%s%s%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__),                                   \
Packit Service 5ffa24
               _NMLOG_PREFIX_NAME,                                                                \
Packit Service 5ffa24
               NM_PRINT_FMT_QUOTED(_ifname, " (", _ifname, ")", "")                               \
Packit Service 5ffa24
                   _NM_UTILS_MACRO_REST(__VA_ARGS__));                                            \
Packit Service 5ffa24
    }                                                                                             \
Packit Service 5ffa24
    G_STMT_END
Packit Service 5ffa24
Packit Service 5ffa24
/*****************************************************************************/
Packit Service 5ffa24
Packit Service 5ffa24
struct NMWpanUtils {
Packit Service 5ffa24
    GObject         parent;
Packit Service 5ffa24
    int             ifindex;
Packit Service 5ffa24
    struct nl_sock *nl_sock;
Packit Service 5ffa24
    int             id;
Packit Service 5ffa24
};
Packit Service 5ffa24
Packit Service 5ffa24
typedef struct {
Packit Service 5ffa24
    GObjectClass parent;
Packit Service 5ffa24
} NMWpanUtilsClass;
Packit Service 5ffa24
Packit Service 5ffa24
G_DEFINE_TYPE(NMWpanUtils, nm_wpan_utils, G_TYPE_OBJECT)
Packit Service 5ffa24
Packit Service 5ffa24
/*****************************************************************************/
Packit Service 5ffa24
Packit Service 5ffa24
static int
Packit Service 5ffa24
ack_handler(struct nl_msg *msg, void *arg)
Packit Service 5ffa24
{
Packit Service 5ffa24
    int *done = arg;
Packit Service 5ffa24
    *done     = 1;
Packit Service 5ffa24
    return NL_STOP;
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static int
Packit Service 5ffa24
finish_handler(struct nl_msg *msg, void *arg)
Packit Service 5ffa24
{
Packit Service 5ffa24
    int *done = arg;
Packit Service 5ffa24
    *done     = 1;
Packit Service 5ffa24
    return NL_SKIP;
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static int
Packit Service 5ffa24
error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
Packit Service 5ffa24
{
Packit Service 5ffa24
    int *done = arg;
Packit Service 5ffa24
    *done     = err->error;
Packit Service 5ffa24
    return NL_SKIP;
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static struct nl_msg *
Packit Service 5ffa24
_nl802154_alloc_msg(int id, int ifindex, guint32 cmd, guint32 flags)
Packit Service 5ffa24
{
Packit Service 5ffa24
    nm_auto_nlmsg struct nl_msg *msg = NULL;
Packit Service 5ffa24
Packit Service 5ffa24
    msg = nlmsg_alloc();
Packit Service 5ffa24
    genlmsg_put(msg, 0, 0, id, 0, flags, cmd, 0);
Packit Service 5ffa24
    NLA_PUT_U32(msg, NL802154_ATTR_IFINDEX, ifindex);
Packit Service 5ffa24
    return g_steal_pointer(&msg;;
Packit Service 5ffa24
Packit Service 5ffa24
nla_put_failure:
Packit Service 5ffa24
    g_return_val_if_reached(NULL);
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static struct nl_msg *
Packit Service 5ffa24
nl802154_alloc_msg(NMWpanUtils *self, guint32 cmd, guint32 flags)
Packit Service 5ffa24
{
Packit Service 5ffa24
    return _nl802154_alloc_msg(self->id, self->ifindex, cmd, flags);
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static int
Packit Service 5ffa24
nl802154_send_and_recv(NMWpanUtils *  self,
Packit Service 5ffa24
                       struct nl_msg *msg,
Packit Service 5ffa24
                       int (*valid_handler)(struct nl_msg *, void *),
Packit Service 5ffa24
                       void *valid_data)
Packit Service 5ffa24
{
Packit Service 5ffa24
    int                err;
Packit Service 5ffa24
    int                done = 0;
Packit Service 5ffa24
    const struct nl_cb cb   = {
Packit Service 5ffa24
        .err_cb     = error_handler,
Packit Service 5ffa24
        .err_arg    = &done,
Packit Service 5ffa24
        .finish_cb  = finish_handler,
Packit Service 5ffa24
        .finish_arg = &done,
Packit Service 5ffa24
        .ack_cb     = ack_handler,
Packit Service 5ffa24
        .ack_arg    = &done,
Packit Service 5ffa24
        .valid_cb   = valid_handler,
Packit Service 5ffa24
        .valid_arg  = valid_data,
Packit Service 5ffa24
    };
Packit Service 5ffa24
Packit Service 5ffa24
    g_return_val_if_fail(msg != NULL, -ENOMEM);
Packit Service 5ffa24
Packit Service 5ffa24
    err = nl_send_auto(self->nl_sock, msg);
Packit Service 5ffa24
    if (err < 0)
Packit Service 5ffa24
        return err;
Packit Service 5ffa24
Packit Service 5ffa24
    /* Loop until one of our NL callbacks says we're done; on success
Packit Service 5ffa24
     * done will be 1, on error it will be < 0.
Packit Service 5ffa24
     */
Packit Service 5ffa24
    while (!done) {
Packit Service 5ffa24
        err = nl_recvmsgs(self->nl_sock, &cb;;
Packit Service 5ffa24
        if (err < 0 && err != -EAGAIN) {
Packit Service 5ffa24
            _LOGW(LOGD_PLATFORM, "nl_recvmsgs() error: (%d) %s", err, nm_strerror(err));
Packit Service 5ffa24
            break;
Packit Service 5ffa24
        }
Packit Service 5ffa24
    }
Packit Service 5ffa24
Packit Service 5ffa24
    if (err >= 0 && done < 0)
Packit Service 5ffa24
        err = done;
Packit Service 5ffa24
    return err;
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
struct nl802154_interface {
Packit Service 5ffa24
    guint16 pan_id;
Packit Service 5ffa24
    guint16 short_addr;
Packit Service 5ffa24
Packit Service 5ffa24
    gboolean valid;
Packit Service 5ffa24
};
Packit Service 5ffa24
Packit Service 5ffa24
static int
Packit Service 5ffa24
nl802154_get_interface_handler(struct nl_msg *msg, void *arg)
Packit Service 5ffa24
{
Packit Service 5ffa24
    static const struct nla_policy nl802154_policy[] = {
Packit Service 5ffa24
        [NL802154_ATTR_PAN_ID]     = {.type = NLA_U16},
Packit Service 5ffa24
        [NL802154_ATTR_SHORT_ADDR] = {.type = NLA_U16},
Packit Service 5ffa24
    };
Packit Service 5ffa24
    struct nlattr *            tb[G_N_ELEMENTS(nl802154_policy)];
Packit Service 5ffa24
    struct nl802154_interface *info = arg;
Packit Service 5ffa24
    struct genlmsghdr *        gnlh = nlmsg_data(nlmsg_hdr(msg));
Packit Service 5ffa24
Packit Service 5ffa24
    if (nla_parse_arr(tb, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), nl802154_policy) < 0)
Packit Service 5ffa24
        return NL_SKIP;
Packit Service 5ffa24
Packit Service 5ffa24
    if (tb[NL802154_ATTR_PAN_ID])
Packit Service 5ffa24
        info->pan_id = le16toh(nla_get_u16(tb[NL802154_ATTR_PAN_ID]));
Packit Service 5ffa24
Packit Service 5ffa24
    if (tb[NL802154_ATTR_SHORT_ADDR])
Packit Service 5ffa24
        info->short_addr = le16toh(nla_get_u16(tb[NL802154_ATTR_SHORT_ADDR]));
Packit Service 5ffa24
Packit Service 5ffa24
    info->valid = TRUE;
Packit Service 5ffa24
Packit Service 5ffa24
    return NL_SKIP;
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
nl802154_get_interface(NMWpanUtils *self, struct nl802154_interface *interface)
Packit Service 5ffa24
{
Packit Service 5ffa24
    nm_auto_nlmsg struct nl_msg *msg = NULL;
Packit Service 5ffa24
Packit Service 5ffa24
    memset(interface, 0, sizeof(*interface));
Packit Service 5ffa24
Packit Service 5ffa24
    msg = nl802154_alloc_msg(self, NL802154_CMD_GET_INTERFACE, 0);
Packit Service 5ffa24
Packit Service 5ffa24
    nl802154_send_and_recv(self, msg, nl802154_get_interface_handler, interface);
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
/*****************************************************************************/
Packit Service 5ffa24
Packit Service 5ffa24
guint16
Packit Service 5ffa24
nm_wpan_utils_get_pan_id(NMWpanUtils *self)
Packit Service 5ffa24
{
Packit Service 5ffa24
    struct nl802154_interface interface;
Packit Service 5ffa24
Packit Service 5ffa24
    nl802154_get_interface(self, &interface);
Packit Service 5ffa24
Packit Service 5ffa24
    return interface.pan_id;
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
gboolean
Packit Service 5ffa24
nm_wpan_utils_set_pan_id(NMWpanUtils *self, guint16 pan_id)
Packit Service 5ffa24
{
Packit Service 5ffa24
    nm_auto_nlmsg struct nl_msg *msg = NULL;
Packit Service 5ffa24
    int                          err;
Packit Service 5ffa24
Packit Service 5ffa24
    g_return_val_if_fail(self != NULL, FALSE);
Packit Service 5ffa24
Packit Service 5ffa24
    msg = nl802154_alloc_msg(self, NL802154_CMD_SET_PAN_ID, 0);
Packit Service 5ffa24
    NLA_PUT_U16(msg, NL802154_ATTR_PAN_ID, htole16(pan_id));
Packit Service 5ffa24
    err = nl802154_send_and_recv(self, msg, NULL, NULL);
Packit Service 5ffa24
    return err >= 0;
Packit Service 5ffa24
Packit Service 5ffa24
nla_put_failure:
Packit Service 5ffa24
    g_return_val_if_reached(FALSE);
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
guint16
Packit Service 5ffa24
nm_wpan_utils_get_short_addr(NMWpanUtils *self)
Packit Service 5ffa24
{
Packit Service 5ffa24
    struct nl802154_interface interface;
Packit Service 5ffa24
Packit Service 5ffa24
    nl802154_get_interface(self, &interface);
Packit Service 5ffa24
Packit Service 5ffa24
    return interface.short_addr;
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
gboolean
Packit Service 5ffa24
nm_wpan_utils_set_short_addr(NMWpanUtils *self, guint16 short_addr)
Packit Service 5ffa24
{
Packit Service 5ffa24
    nm_auto_nlmsg struct nl_msg *msg = NULL;
Packit Service 5ffa24
    int                          err;
Packit Service 5ffa24
Packit Service 5ffa24
    g_return_val_if_fail(self != NULL, FALSE);
Packit Service 5ffa24
Packit Service 5ffa24
    msg = nl802154_alloc_msg(self, NL802154_CMD_SET_SHORT_ADDR, 0);
Packit Service 5ffa24
    NLA_PUT_U16(msg, NL802154_ATTR_SHORT_ADDR, htole16(short_addr));
Packit Service 5ffa24
    err = nl802154_send_and_recv(self, msg, NULL, NULL);
Packit Service 5ffa24
    return err >= 0;
Packit Service 5ffa24
Packit Service 5ffa24
nla_put_failure:
Packit Service 5ffa24
    g_return_val_if_reached(FALSE);
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
gboolean
Packit Service 5ffa24
nm_wpan_utils_set_channel(NMWpanUtils *self, guint8 page, guint8 channel)
Packit Service 5ffa24
{
Packit Service 5ffa24
    nm_auto_nlmsg struct nl_msg *msg = NULL;
Packit Service 5ffa24
    int                          err;
Packit Service 5ffa24
Packit Service 5ffa24
    g_return_val_if_fail(self != NULL, FALSE);
Packit Service 5ffa24
Packit Service 5ffa24
    msg = nl802154_alloc_msg(self, NL802154_CMD_SET_CHANNEL, 0);
Packit Service 5ffa24
    NLA_PUT_U8(msg, NL802154_ATTR_PAGE, page);
Packit Service 5ffa24
    NLA_PUT_U8(msg, NL802154_ATTR_CHANNEL, channel);
Packit Service 5ffa24
    err = nl802154_send_and_recv(self, msg, NULL, NULL);
Packit Service 5ffa24
    return err >= 0;
Packit Service 5ffa24
Packit Service 5ffa24
nla_put_failure:
Packit Service 5ffa24
    g_return_val_if_reached(FALSE);
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
/*****************************************************************************/
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
nm_wpan_utils_init(NMWpanUtils *self)
Packit Service 5ffa24
{}
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
nm_wpan_utils_class_init(NMWpanUtilsClass *klass)
Packit Service 5ffa24
{}
Packit Service 5ffa24
Packit Service 5ffa24
NMWpanUtils *
Packit Service 5ffa24
nm_wpan_utils_new(int ifindex, struct nl_sock *genl, gboolean check_scan)
Packit Service 5ffa24
{
Packit Service 5ffa24
    NMWpanUtils *self;
Packit Service 5ffa24
Packit Service 5ffa24
    g_return_val_if_fail(ifindex > 0, NULL);
Packit Service 5ffa24
Packit Service 5ffa24
    if (!genl)
Packit Service 5ffa24
        return NULL;
Packit Service 5ffa24
Packit Service 5ffa24
    self          = g_object_new(NM_TYPE_WPAN_UTILS, NULL);
Packit Service 5ffa24
    self->ifindex = ifindex;
Packit Service 5ffa24
    self->nl_sock = genl;
Packit Service 5ffa24
    self->id      = genl_ctrl_resolve(genl, "nl802154");
Packit Service 5ffa24
Packit Service 5ffa24
    if (self->id < 0) {
Packit Service 5ffa24
        _LOGD(LOGD_PLATFORM, "genl_ctrl_resolve: failed to resolve \"nl802154\"");
Packit Service 5ffa24
        g_object_unref(self);
Packit Service 5ffa24
        return NULL;
Packit Service 5ffa24
    }
Packit Service 5ffa24
Packit Service 5ffa24
    return self;
Packit Service 5ffa24
}