xref: /aosp_15_r20/external/iw/hwsim.c (revision 92022041c981f431db0b590d0c3272306d0ea2a2)
1 #include <errno.h>
2 #include <string.h>
3 
4 #include <netlink/genl/genl.h>
5 #include <netlink/genl/family.h>
6 #include <netlink/genl/ctrl.h>
7 #include <netlink/msg.h>
8 #include <netlink/attr.h>
9 
10 #include "nl80211.h"
11 #include "iw.h"
12 
13 /* These enums need to be kept in sync with the kernel */
14 enum hwsim_testmode_attr {
15 	__HWSIM_TM_ATTR_INVALID	= 0,
16 	HWSIM_TM_ATTR_CMD	= 1,
17 	HWSIM_TM_ATTR_PS	= 2,
18 
19 	/* keep last */
20 	__HWSIM_TM_ATTR_AFTER_LAST,
21 	HWSIM_TM_ATTR_MAX	= __HWSIM_TM_ATTR_AFTER_LAST - 1
22 };
23 
24 enum hwsim_testmode_cmd {
25 	HWSIM_TM_CMD_SET_PS		= 0,
26 	HWSIM_TM_CMD_GET_PS		= 1,
27 	HWSIM_TM_CMD_STOP_QUEUES	= 2,
28 	HWSIM_TM_CMD_WAKE_QUEUES	= 3,
29 };
30 
31 
32 SECTION(hwsim);
33 
print_hwsim_ps_handler(struct nl_msg * msg,void * arg)34 static int print_hwsim_ps_handler(struct nl_msg *msg, void *arg)
35 {
36 	struct nlattr *attrs[NL80211_ATTR_MAX + 1];
37 	struct nlattr *tb[HWSIM_TM_ATTR_MAX + 1];
38 	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
39 
40 	nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
41 		  genlmsg_attrlen(gnlh, 0), NULL);
42 
43 	if (!attrs[NL80211_ATTR_TESTDATA])
44 		return NL_SKIP;
45 
46 	nla_parse(tb, HWSIM_TM_ATTR_MAX, nla_data(attrs[NL80211_ATTR_TESTDATA]),
47 		  nla_len(attrs[NL80211_ATTR_TESTDATA]), NULL);
48 
49 	printf("HWSIM PS: %d\n", nla_get_u32(tb[HWSIM_TM_ATTR_PS]));
50 
51 	return NL_SKIP;
52 }
53 
handle_hwsim_getps(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)54 static int handle_hwsim_getps(struct nl80211_state *state,
55 			      struct nl_msg *msg, int argc, char **argv,
56 			      enum id_input id)
57 {
58 	struct nlattr *tmdata;
59 
60 	tmdata = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
61 	if (!tmdata)
62 		goto nla_put_failure;
63 
64 	NLA_PUT_U32(msg, HWSIM_TM_ATTR_CMD, HWSIM_TM_CMD_GET_PS);
65 
66 	nla_nest_end(msg, tmdata);
67 
68 	register_handler(print_hwsim_ps_handler, NULL);
69 	return 0;
70  nla_put_failure:
71 	return -ENOBUFS;
72 }
73 COMMAND(hwsim, getps, "", NL80211_CMD_TESTMODE, 0, CIB_PHY, handle_hwsim_getps, "");
74 
handle_hwsim_setps(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)75 static int handle_hwsim_setps(struct nl80211_state *state,
76 			      struct nl_msg *msg, int argc, char **argv,
77 			      enum id_input id)
78 {
79 	struct nlattr *tmdata;
80 	__u32 ps;
81 	char *end;
82 
83 	if (argc != 1)
84 		return 1;
85 
86 	ps = strtoul(argv[0], &end, 0);
87 	if (*end)
88 		return 1;
89 
90 	tmdata = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
91 	if (!tmdata)
92 		goto nla_put_failure;
93 
94 	NLA_PUT_U32(msg, HWSIM_TM_ATTR_CMD, HWSIM_TM_CMD_SET_PS);
95 	NLA_PUT_U32(msg, HWSIM_TM_ATTR_PS, ps);
96 
97 	nla_nest_end(msg, tmdata);
98 
99 	register_handler(print_hwsim_ps_handler, NULL);
100 	return 0;
101  nla_put_failure:
102 	return -ENOBUFS;
103 }
104 COMMAND(hwsim, setps, "<value>", NL80211_CMD_TESTMODE, 0, CIB_PHY, handle_hwsim_setps, "");
105 
handle_hwsim_stop_queues(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)106 static int handle_hwsim_stop_queues(struct nl80211_state *state,
107 				    struct nl_msg *msg, int argc, char **argv,
108 				    enum id_input id)
109 {
110 	struct nlattr *tmdata;
111 
112 	if (argc != 0)
113 		return 1;
114 
115 	tmdata = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
116 	if (!tmdata)
117 		goto nla_put_failure;
118 
119 	NLA_PUT_U32(msg, HWSIM_TM_ATTR_CMD, HWSIM_TM_CMD_STOP_QUEUES);
120 
121 	nla_nest_end(msg, tmdata);
122 	return 0;
123  nla_put_failure:
124 	return -ENOBUFS;
125 }
126 COMMAND(hwsim, stopqueues, "", NL80211_CMD_TESTMODE, 0, CIB_PHY, handle_hwsim_stop_queues, "");
127 
handle_hwsim_wake_queues(struct nl80211_state * state,struct nl_msg * msg,int argc,char ** argv,enum id_input id)128 static int handle_hwsim_wake_queues(struct nl80211_state *state,
129 				    struct nl_msg *msg, int argc, char **argv,
130 				    enum id_input id)
131 {
132 	struct nlattr *tmdata;
133 
134 	if (argc != 0)
135 		return 1;
136 
137 	tmdata = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
138 	if (!tmdata)
139 		goto nla_put_failure;
140 
141 	NLA_PUT_U32(msg, HWSIM_TM_ATTR_CMD, HWSIM_TM_CMD_WAKE_QUEUES);
142 
143 	nla_nest_end(msg, tmdata);
144 	return 0;
145  nla_put_failure:
146 	return -ENOBUFS;
147 }
148 COMMAND(hwsim, wakequeues, "", NL80211_CMD_TESTMODE, 0, CIB_PHY, handle_hwsim_wake_queues, "");
149