Skip to content

Introduce TA WIFI agent library#3

Open
maximmenshikov wants to merge 5 commits into
ts-factory:mainfrom
interpretica-io:mmenshikov/ta_wifi
Open

Introduce TA WIFI agent library#3
maximmenshikov wants to merge 5 commits into
ts-factory:mainfrom
interpretica-io:mmenshikov/ta_wifi

Conversation

@maximmenshikov

Copy link
Copy Markdown

This test agent library adds an ability to set up the WiFi configuration using UCI and hostapd/wpa_supplicant (eventually).

It is based on the design & requirements by Elena V.

The main idea is that there is a very small set of options in the configurator tree. This set of options is merged into the real UCI configuration that is already present on the test host. Then, the "wifi up" is called to restart the network on the device.

@maximmenshikov maximmenshikov force-pushed the mmenshikov/ta_wifi branch 5 times, most recently from 631fa7a to 986c493 Compare August 22, 2025 12:39
@ol-arteman

Copy link
Copy Markdown
Collaborator

Comment thread lib/ta_wifi/ta_wifi.c Outdated
Comment thread lib/ta_wifi/ta_wifi.c Outdated
Comment on lines +676 to +677
rc = te_strtou_size(value, 0, &val,
sizeof(val));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can definitely fit into one line.

Comment thread lib/ta_wifi/ta_wifi.c Outdated
if (port == NULL)
return TE_RC(TE_TA_UNIX, TE_ENOENT);

port->enable = (atoi(value) > 0) ? true : false;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

te_strtol_bool ?

Comment thread lib/ta_wifi/ta_wifi.c Outdated
Comment thread lib/ta_wifi/ta_wifi.c Outdated

port->enable = (atoi(value) > 0) ? true : false;

return ta_unix_conf_wifi_apply();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should implement commit method instead.

Comment thread lib/ta_wifi/ta_wifi_uci_apply.c Outdated
Comment on lines +43 to +48
.f = NULL, \
.radio_instance = 0, \
.iface_instance = 0, \
.port = NULL, \
.tmpl_data = NULL, \
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Misaligned backslashes.

Comment thread lib/ta_wifi/ta_wifi_uci_parser.c Outdated
Comment on lines +182 to +205
int n = 0;
char *tok[3] = {0};
char *p;

p = strtok(line, " \t\r\n");
while (p && n < 3)
{
if (*p == '\'' && p[strlen(p) - 1] == '\'' && strlen(p) > 1)
{
p[strlen(p) - 1] = 0;
p++;
}
tok[n++] = p;
if (n == 2)
{
p = strtok(NULL, "\n");
}
else
{
p = strtok(NULL, " \t\r\n");
}
}

if (n == 3)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

te_vec_split_string() ?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Obviously this function is not suitable. I will, however, introduce string->vec tokenizer.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tokenizer is introduced

@ol-arteman

Copy link
Copy Markdown
Collaborator

Also, we do already have tapi_wifi. I would like to hear some rationale why we would need a parallel set of API for the same task.

Comment thread doc/cm/cm_wifi.yml
Name: empty
Value: 0 or 1

- oid: "/agent/wifi/port/ifname"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be related to /agent/interface in some way/

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather SSID is related.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ol-arteman in general it is not guaranteed that the port would always be mapped to the existing interface. Depending on configurator, it may run it later, making it impossible to bind to.

Comment thread doc/cm/cm_wifi.yml
Root object of the WiFi configuration tree.
Name: empty

- oid: "/agent/wifi/port"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I bet it should be a resource.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also the same problem - it could be non-existing interface and thus we can't bind it easily.
@evengerova please tell what you think.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically PHYs are created on startup and may be really be considered as resources. Of course in theory we can load kernel modules later, but IMHO it's not that probable.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ports are indexed by user-friendly name, therefore it is not feasible to add them to resources (ifname might not be the same as the instance name)

Comment thread doc/cm/cm_wifi.yml
Comment on lines +87 to +95
Name: Internal SSID name

- oid: "/agent/wifi/port/ssid/aname"
access: read_write
type: string
d: |
SSID name.
Name: empty
Value: SSID name

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why aname ? And why do we need a SSID name as an attribute if we have a SSID name as a name of an instance?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Internal SSID name is something we can index SSIDs by, while real SSID name is something that is passed over the air.

Comment thread doc/cm/cm_wifi.yml
Comment on lines +129 to +143
- oid: "/agent/wifi/port/ssid/option"
access: read_create
type: none
d: |
Additional options passed to underlying configurator.
Name: any
Value: none

- oid: "/agent/wifi/port/ssid/option/value"
access: read_write
type: string
d: |
Value of the option passed to underlying configurator.
Name: empty
Value: any option permitted by underlying configurator.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am kind of skeptic of this design. It pretends to be kind of backend-neutral, but it's actually not - there is absolutely no warrant that all possible wifi configurators can be expressed with a simple option-value scheme. Also, there is no introspection: the testsuite has no way of learning which options are supported.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no fundamentally good solution to the problem of representability. It is up to particular configurator to make this scheme work.

Comment thread doc/cm/cm_wifi.yml
Root object of the WiFi configuration tree.
Name: empty

- oid: "/agent/wifi/configurator"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary? Isn't it's possible to do auto-detection?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is possible to auto detect, but it is impossible to make wise and reproducible decision with autodetection.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? Let's at least allow to keep this field empty to get auto detection.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

auto detection is added

Comment thread doc/cm/cm_wifi.yml
Name: empty
Value: 0 or 1

- oid: "/agent/wifi/port"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not possible to add a port.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed it is possible. It is not autodetected from the configuration, and realistically there may be configurators that would run interface afterwards.

Comment thread doc/cm/cm_wifi.yml
Name: empty
Value: 0 or 1

- oid: "/agent/wifi/port/ifname"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather SSID is related.

Comment thread doc/cm/cm_wifi.yml Outdated
Name: empty
Value: Channel number

- oid: "/agent/wifi/port/htmode"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

htmode is UCI-specific thing. Ive asked (and Misha has done) channel width - number 20/40/80/160

Comment thread doc/cm/cm_wifi.yml Outdated
Name: empty
Value: Any supported by Linux

- oid: "/agent/wifi/port/ssid/aname"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"ssid" is better

Comment thread doc/cm/cm_wifi.yml
d: |
SSID security.
Name: empty
Value: open, wpa, wpa2, wpa3

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wep is missing

Comment thread doc/cm/cm_wifi.yml
Name: empty
Value: Passphrase 8 to 63 characters long

- oid: "/agent/wifi/port/ssid/option"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not like OS-specific and hw-specific options. From the other hand it's not quite clear how to get default values for mandatory things.

Comment thread lib/ta_wifi/ta_wifi_internal.h Outdated

/** Supported WiFi standards */
typedef enum ta_wifi_standard {
TA_WIFI_STANDARD_G = 0, /**< G standard (2.4GHz) */

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AX and BE are applied for both 2.4 and 5.


#include "te_queue.h"

#define MAX_LINE (1024)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wonder why do we need parser if there is an API (or in the worst case CLI). But, I suppose, it's too late...

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra dependencies is always a bad idea

@evengerova

Copy link
Copy Markdown
Collaborator

Also, we do already have tapi_wifi. I would like to hear some rationale why we would need a parallel set of API for the same task.

Because tapi_wifi is not generic, but operates Linux-specific wpa_supplicant concepts. Also does not support AP.

@ol-arteman

Copy link
Copy Markdown
Collaborator

New and updated commits still do not conform to our Contributor's Guide. There is a script scripts/te_check_patches that can be used to validate them.

Also I would really appreciate it if fixup commits were squashed into their base commits.

@maximmenshikov

Copy link
Copy Markdown
Author

New and updated commits still do not conform to our Contributor's Guide. There is a script scripts/te_check_patches that can be used to validate them.

Also I would really appreciate it if fixup commits were squashed into their base commits.

I didn't say it is ready for a new review (there are several projects that depend on that branch and all of them have to be verified) and I haven't marked your request as processed in any way.

@ol-arteman

Copy link
Copy Markdown
Collaborator

May I also ask for some close-to-real-world examples of an instance tree?

@maximmenshikov

Copy link
Copy Markdown
Author

May I also ask for some close-to-real-world examples of an instance tree?

    RING("Enable wpa supplicant mode");
    CHECK_RC(cfg_set_instance_fmt(CFG_VAL(STRING, "hostapd_wpa_supplicant"),
                                  "/agent:%s/wifi:/configurator:",
                                  host->ta));

    RING("Add WiFi port");
    CHECK_RC(cfg_add_instance_fmt(&port_handle,
                                  CFG_VAL(NONE, NULL),
                                  "/agent:%s/wifi:/port:wifi",
                                  host->ta));

    RING("Set WiFi port interface");
    CHECK_RC(cfg_set_instance_fmt(CFG_VAL(STRING, conf->iface_wifi_a),
                                  "/agent:%s/wifi:/port:wifi/ifname:",
                                  host->ta));

    RING("Set WiFi port HT mode");
    CHECK_RC(cfg_set_instance_fmt(CFG_VAL(INTEGER,
                                          (std == TSAPI_WIFI_STD_G ||
                                           std == TSAPI_WIFI_STD_N)
                                            ? 20
                                            : 80),
                                  "/agent:%s/wifi:/port:wifi/width:",
                                  host->ta));

    RING("Set WiFi port standard");
    CHECK_RC(cfg_set_instance_fmt(CFG_VAL(STRING, tsapi_wifi_std2str(std)),
                                  "/agent:%s/wifi:/port:wifi/standard:",
                                  host->ta));

    RING("Set WiFi port interface enable status");
    CHECK_RC(cfg_set_instance_fmt(CFG_VAL(INTEGER, 1),
                                  "/agent:%s/wifi:/port:wifi/enable:",
                                  host->ta));

    RING("Add WiFi SSID");
    CHECK_RC(cfg_add_instance_fmt(&ssid_handle,
                                  CFG_VAL(NONE, NULL),
                                  "/agent:%s/wifi:/port:wifi/ssid:ssid1",
                                  host->ta));

    RING("Set WiFi SSID sta mode");
    CHECK_RC(cfg_set_instance_fmt(CFG_VAL(STRING, "sta"),
                                  "/agent:%s/wifi:/port:wifi/ssid:ssid1/mode:",
                                  host->ta));

    RING("Set WiFi SSID name");
    CHECK_RC(cfg_set_instance_fmt(CFG_VAL(STRING, tsapi_wifi_get_ssid(conf, std)),
                                  "/agent:%s/wifi:/port:wifi/ssid:ssid1/name:",
                                  host->ta));
    if (conf->dut_wifi_ssid_passphrase == NULL ||
        strlen(conf->dut_wifi_ssid_passphrase) == 0)
    {
        RING("Disable passphrase");
        CHECK_RC(cfg_set_instance_fmt(CFG_VAL(STRING, "open"),
                                      "/agent:%s/wifi:/port:wifi/ssid:ssid1/security:",
                                      host->ta));
    }
    else
    {
        RING("Enable passphrase");
        CHECK_RC(cfg_set_instance_fmt(CFG_VAL(STRING, std == TSAPI_WIFI_STD_BE ? "wpa3" : "wpa2"),
                                      "/agent:%s/wifi:/port:wifi/ssid:ssid1/security:",
                                      host->ta));
        CHECK_RC(cfg_set_instance_fmt(CFG_VAL(STRING, conf->dut_wifi_ssid_passphrase),
                                      "/agent:%s/wifi:/port:wifi/ssid:ssid1/passphrase:",
                                      host->ta));
    }

    CHECK_RC(cfg_set_instance_fmt(CFG_VAL(STRING, "ccmp"),
                                  "/agent:%s/wifi:/port:wifi/ssid:ssid1/protocol:",
                                  host->ta));

    RING("Set WiFi SSID enable status");
    CHECK_RC(cfg_set_instance_fmt(CFG_VAL(INTEGER, 1),
                                  "/agent:%s/wifi:/port:wifi/ssid:ssid1/enable:",
                                  host->ta));

    RING("Enable WiFi");
    CHECK_RC(cfg_set_instance_fmt(CFG_VAL(INTEGER, 1),
                                  "/agent:%s/wifi:/enable:",
                                  host->ta));

Signed-off-by: Maxim Menshikov <maxim.menshikov@interpretica.io>
Acked-by: Elena Vengerova <elena.vengerova@aprocsys.com>
Signed-off-by: Maxim Menshikov <maxim.menshikov@interpretica.io>
Acked-by: Elena Vengerova <elena.vengerova@aprocsys.com>
This is the first bit to enable configuration of WiFi -
generic definitions that should be used in both tests and
the agent implementation.

Signed-off-by: Maxim Menshikov <maxim.menshikov@interpretica.io>
Acked-by: Elena Vengerova <elena.vengerova@aprocsys.com>
@maximmenshikov

Copy link
Copy Markdown
Author

@ol-arteman we may continue this public execution I think.
There were a few real-world checks by Michael K. and Elena V., a few comments by Konstantin U. to help define naming for tapi_cfg_wifi, among a few other things.
Finally, the commits are squashed & properly split according to contributor's guide.

I also merged wpa_supplicant configuration code here.

Comment thread lib/ta_wifi/ta_wifi.c

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return 0 in NOK case looks wrong for me, wpa_supplicat failed to start,
there is "Failed to start WPA Supplicant" printout
but
"Set /agent:agt_wifi_d/wifi:/enable: = 1"
succeeded and test fails later then it should.

I've looked at another commits,
g 'commit(unsigned int gid' .
they all return rc in NOK case.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's about node_wifi_commit()

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning 0 may break TA and it is not what you expect. You should rather check status before continuing.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you elaborate?
0 is returned in NOK case now and I propose to fix it

@maximmenshikov maximmenshikov force-pushed the mmenshikov/ta_wifi branch 2 times, most recently from edea483 to 1e8b669 Compare September 30, 2025 22:15
TA WiFi is based on several concepts:
 - It tries to be backend-agnostic. Right now, UCI and
   wpa_supplicant are supported.
 - It still supports backend-specific optinons. It is clear
   that real-world devices require unique options that
   can't be covered by unified set of options.
 - The backend is auto-detected by default but can be fixed
   to one of them.

For UCI, there are several implications:
 - The configuration is first read, then augmented. To
   generate it correctly, the port interface name must
   match the one in the configuration.
 - The SSID configuration is based on the first SSID from
   the configuration that matches the band of the port.
 - The configuration must reside in /etc/config/wireless.
 - The script to up/down the interfaces is 'wifi up'.

For wpa_supplicant, the binary must reside in
/usr/sbin/wpa_supplicant.

For hostapd, the binary must reside in
/usr/sbin/hostapd

Signed-off-by: Maxim Menshikov <maxim.menshikov@interpretica.io>
Acked-by: Elena Vengerova <elena.vengerova@aprocsys.com>
Signed-off-by: Maxim Menshikov <maxim.menshikov@interpretica.io>
Acked-by: Elena Vengerova <elena.vengerova@aprocsys.com>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t know openwrt logic well, but to me, a safer approach is:

  • "wifi down" with old /etc/config/wireless
  • update /etc/config/wireless
  • wifi up

I’m encountering a rare test failure and suspect that the old iface conflicts with the new one.
However, I have no proof, and the issue is quite rare.

Comment thread lib/ta_wifi/ta_wifi.c

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you elaborate?
0 is returned in NOK case now and I propose to fix it

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about txpower, frag, rts, and other test written options?
I suspect they multiply as well e.g.

first run txpower = 10,
second run txpower = 20 and it produces
option txpower 10
option txpower 20

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is more correct to take ssid's protocol into account

-    CHECKED_FPRINTF(ctx->f, "\toption encryption '%s'\n",
-        wifi_security2enc[node->security]);
+    CHECKED_FPRINTF(ctx->f, "\toption encryption '%s+%s'\n",
+        wifi_security2enc[node->security],
+        tapi_cfg_wifi_protocol_from_value(node->protocol));

to get psk2+tkip, psk2+ccmp
https://openwrt.org/docs/guide-user/network/wifi/basic#encryption_modes

}

/* See the description in tapi_cfg_wifi.h */
tapi_cfg_wifi_standard

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here and in a header
tapi_cfg_wifi_standard -> tapi_cfg_wifi_width

}

/* See the description in tapi_cfg_wifi.h */
tapi_cfg_wifi_mode

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here and in a header
tapi_cfg_wifi_mode -> tapi_cfg_wifi_protocol

There are more notes, but I don't remember them,
nobody in the office and bolger with my home offline.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants