0

Running the following program via: ./main 0 5220 gives me an error that my input data is out of range.

sudo ./main 0 5220               
--------------------------   BEGIN NETLINK MESSAGE ---------------------------
  [NETLINK HEADER] 16 octets
    .nlmsg_len = 52
    .type = 34 <0x22>
    .flags = 5 <REQUEST,ACK>
    .seq = 1667899004
    .port = 683673755
  [GENERIC NETLINK HEADER] 4 octets
    .cmd = 102
    .version = 0
    .unused = 0
  [PAYLOAD] 32 octets
    08 00 01 00 00 00 00 00 08 00 b7 00 02 00 00 00 ................
    08 00 26 00 6c 09 00 00 08 00 9f 00 01 00 00 00 ..&.l...........
---------------------------  END NETLINK MESSAGE   ---------------------------
nl_recvmsgs_default() error (Invalid input data or parameter)
        error

channel switch works fine with: sudo hostapd_cli chan_switch 8 5220

iw dev output of the AP:

phy#0
        Interface wlan0
                ifindex 3
                wdev 0x1
                addr 02:00:00:00:00:00
                ssid apname
                type AP
                channel 1 (2412 MHz), width: 20 MHz, center1: 2412 MHz
                txpower 20.00 dBm

the AP is running via hwsim, shouldn't matter because chan switch works with hostapd_cli

here is the code, I also tried with and without nla_nest_start() & nla_nest_end() argv[1] is the phy#, tried with ifindex 3 but same error argv[2] is the frequency to set

#include <linux/nl80211.h>
#include <netlink/genl/ctrl.h>
#include <netlink/genl/genl.h>

typedef struct nl_element {
    int     id;
    struct nl_sock *socket;
    struct nl_msg * message;
    struct nl_cb *  callback;
} nl_el;

int main(int argc, char *argv[])
{
    int error = 0;
    int retval = 1;
    // struct nlattr *chan;    // used in nla_nest_start() and nla_nest_end()
    nl_el nl = { 0 };

    if (argc < 3) {
        printf("main <phy#> <freq>");
        return -99;
    }

    nl.message = nlmsg_alloc();
    if (nl.message == NULL)
        return -1;

    nl.socket = nl_socket_alloc();
    if (nl.socket == NULL)
        return -2;

    if (genl_connect(nl.socket))
        return -3;

    if (nl_socket_set_buffer_size(nl.socket, 8192, 8192))
        return -4;

    if (setsockopt(nl_socket_get_fd(nl.socket), SOL_NETLINK, NETLINK_EXT_ACK, &retval, sizeof(retval)))
        return -5;

    nl.id = genl_ctrl_resolve(nl.socket, "nl80211");
    if (nl.id < 0)
        return -6;

    // using NL80211_CMD_SET_WIPHY instead of NL80211_CMD_CHANNEL_SWITCH gives error message:
    // nl_recvmsgs_default() error (Object busy)
    if (genlmsg_put(nl.message, 0, 0, nl.id, 0, NLM_F_REQUEST, NL80211_CMD_CHANNEL_SWITCH, 0) == NULL)
        return -7;

    NLA_PUT_S32(nl.message, NL80211_ATTR_WIPHY, atoi(argv[1]));

    // chan = nla_nest_start(nl.message, NL80211_PMSR_PEER_ATTR_CHAN);

    // NLA_PUT_FLAG(nl.message, NL80211_ATTR_CH_SWITCH_BLOCK_TX); // either this or NL80211_ATTR_CH_SWITCH_COUNT
    NLA_PUT_U32(nl.message, NL80211_ATTR_CH_SWITCH_COUNT, 2);
    NLA_PUT_S32(nl.message, NL80211_ATTR_WIPHY_FREQ, atoi(argv[2]));
    NLA_PUT_U32(nl.message, NL80211_ATTR_CHANNEL_WIDTH, NL80211_CHAN_HT20);
    // NLA_PUT_S32(nl.message, NL80211_ATTR_CENTER_FREQ1, 5180);
    // NLA_PUT_S32(nl.message, NL80211_ATTR_WIPHY_FREQ_OFFSET, 0);
    // NLA_PUT_U32(nl.message, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_NO_HT);    // deprecated

    // nla_nest_end(nl.message, chan);

    if (nl_send_auto(nl.socket, nl.message) < 0)
        return -8;

    nl_msg_dump(nl.message, stdout);

    printf("\n error: %s \n", nl_geterror(nl_recvmsgs_default(nl.socket)));

    return 0;

nla_put_failure:
    return -10;
}

to build: gcc main.c $(pkg-config --cflags --libs libnl-3.0 libnl-genl-3.0)

Is the problem maybe the fact that via nl80211 one has to put the interface DOWN before switching channel?

gathered the information here

precla
  • 36
  • 5

1 Answers1

0

are you sure NL80211_ATTR_WIPHY is the right way to identify, which interface shall be the destination of your command? i wonder if it shall use NL80211_ATTR_IFINDEX, same as in NL80211_CMD_SET_CHANNEL command.

Igor Stasenko
  • 1,037
  • 5
  • 8
  • getting `resource busy` when using NL80211_ATTR_IFINDEX and NL80211_CMD_SET_INTERFACE (same with NL80211_CMD_SET_WIPHY or NL80211_CMD_SET_CHANNEL). – precla Jan 16 '23 at 11:06
  • well, that probably a response from the driver/logic layer, if your interface in managed mode and joined BSS then of course, it will refuse to switch frequency willy-nilly. at least 'resource busy' error indicates that your message properly formed, in contrast to error that you had before. I tried switching frequency while in monitor mode, works fine: sudo iw phy phy15 set freq 5500 HT20 sudo iw phy phy15 set freq 5180 HT20 – Igor Stasenko Jan 21 '23 at 07:41
  • All was tested on a `type AP` interface. Getting `command failed: Device or resource busy (-16)` when trying to change via `iw dev wlan0 set channel 4` (current channel set by hostapd is 2). Does work with `iw` when i set the interface to `down`, but my goal is to switch the channel while having an active AP - therefor `NL80211_CMD_CHANNEL_SWITCH`. The commands `iw dev wlan0 switch channel 5 NOHT20 beacons 4` , or `iw dev wlan0 switch channel 5 HT20 block-tx` or `sudo iw dev wlan0 switch freq 2427 HT20 beacons 4` return: `command failed: Invalid argument (-22)` – precla Jan 22 '23 at 19:14