blob: ec0a3208dad4089ae440aa3370536dc08ee9a88e [file] [log] [blame]
developer3abe1ad2022-01-24 11:13:32 +08001/* Copyright (C) 2021-2022 Mediatek Inc. */
2
3#include <signal.h>
4#include <sys/select.h>
5#include <sys/wait.h>
6#include "atenl.h"
7
8static const char *progname;
9bool atenl_enable;
10
11void sig_handler(int signum)
12{
13 atenl_enable = false;
14}
15
16void atenl_init_signals()
17{
18 if (signal(SIGINT, sig_handler) == SIG_ERR)
19 goto out;
20 if (signal(SIGTERM, sig_handler) == SIG_ERR)
21 goto out;
22 if (signal(SIGABRT, sig_handler) == SIG_ERR)
23 goto out;
24 if (signal(SIGUSR1, sig_handler) == SIG_ERR)
25 goto out;
26 if (signal(SIGUSR2, sig_handler) == SIG_ERR)
27 goto out;
28
29 return;
30out:
31 perror("signal");
32}
33
34static int phy_lookup_idx(const char *name)
35{
36 char buf[128];
37 FILE *f;
38 size_t len;
39 int ret;
40
41 ret = snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name);
42 if (snprintf_error(sizeof(buf), ret))
43 return -1;
44
45 f = fopen(buf, "r");
46 if (!f)
47 return -1;
48
49 len = fread(buf, 1, sizeof(buf) - 1, f);
50 fclose(f);
51
52 if (!len)
53 return -1;
54
55 buf[len] = 0;
56 return atoi(buf);
57}
58
59static void usage(void)
60{
61 fprintf(stderr, "Usage:\n");
62 printf(" %s [-u] [-i phyX]\n", progname);
63 printf("options:\n"
64 " -h = show help text\n"
65 " -i = phy name of driver interface, please use first phy for dbdc\n"
66 " -u = use unicast to respond to HQADLL\n");
67 printf("examples:\n"
68 " %s -u -i phy0\n", progname);
69
70 exit(EXIT_FAILURE);
71}
72
73static int atenl_parent_work(struct atenl *an)
74{
75 int sock_eth = an->sock_eth;
76 int count, ret = 0;
77 fd_set readfds;
78
79 atenl_info("[%d]%s: start for receiving HQA commands\n", getpid(), __func__);
80
81 while (atenl_enable) {
82 FD_ZERO(&readfds);
83 FD_SET(sock_eth, &readfds);
84 count = select(sock_eth + 1, &readfds, NULL, NULL, NULL);
85
86 if (count < 0) {
87 atenl_err("%s: select failed, %s\n", __func__, strerror(errno));
88 continue;
89 } else if (count == 0) {
90 usleep(1000);
91 continue;
92 } else {
93 if (FD_ISSET(sock_eth, &readfds)) {
94 struct atenl_data *data = calloc(1, sizeof(struct atenl_data));
95
96 ret = atenl_eth_recv(an, data);
97 if (ret) {
98 kill(an->child_pid, SIGUSR1);
99 return ret;
100 }
101
102 ret = atenl_hqa_recv(an, data);
103 if (ret < 0) {
104 kill(an->child_pid, SIGUSR1);
105 return ret;
106 }
107
108 free(data);
109 }
110 }
111 }
112
113 atenl_info("[%d]%s: parent work end\n", getpid(), __func__);
114
115 return ret;
116}
117
118static int atenl_child_work(struct atenl *an)
119{
120 int rfd = an->pipefd[PIPE_READ], count;
121 int ret = 0;
122 fd_set readfds;
123
124 atenl_info("[%d]%s: start for sending back results\n", getpid(), __func__);
125
126 while (atenl_enable) {
127 struct atenl_data *data = calloc(1, sizeof(struct atenl_data));
128
129 FD_ZERO(&readfds);
130 FD_SET(rfd, &readfds);
131
132 count = select(FD_SETSIZE, &readfds, NULL, NULL, NULL);
133
134 if (count < 0) {
135 atenl_err("%s: select failed, %s\n", __func__, strerror(errno));
136 continue;
137 } else if (count == 0) {
138 usleep(1000);
139 continue;
140 } else {
141 if (FD_ISSET(rfd, &readfds)) {
142 count = read(rfd, data->buf, RACFG_PKT_MAX_SIZE);
143 atenl_dbg("[%d]PIPE Read %d bytes\n", getpid(), count);
144
145 if (count < 0) {
146 atenl_info("%s: %s\n", __func__, strerror(errno));
147 } else if (count == 0) {
148 continue;
149 } else {
150 int ret;
151
152 ret = atenl_hqa_proc_cmd(an, data);
153 if (ret) {
154 kill(getppid(), SIGUSR2);
155 goto out;
156 }
157
158 ret = atenl_eth_send(an, data);
159 if (ret) {
160 kill(getppid(), SIGUSR2);
161 goto out;
162 }
163 }
164 }
165 }
166 }
167
168out:
169 atenl_info("[%d]%s: child work end\n", getpid(), __func__);
170
171 return ret;
172}
173
174int main(int argc, char **argv)
175{
176 int opt, phy_idx, ret = 0;
177 char *phy = "phy0", *cmd = NULL;
178 struct atenl *an;
179
180 progname = argv[0];
181
182 an = calloc(1, sizeof(struct atenl));
183 if (!an)
184 return -ENOMEM;
185
186 while(1) {
187 opt = getopt(argc, argv, "hi:uc:");
188 if (opt == -1)
189 break;
190
191 switch (opt) {
192 case 'h':
193 usage();
194 free(an);
195 return 0;
196 case 'i':
197 phy = optarg;
198 break;
199 case 'u':
200 an->unicast = true;
201 printf("Opt: use unicast to send response\n");
202 break;
203 case 'c':
204 cmd = optarg;
205 break;
206 default:
207 fprintf(stderr, "Not supported option\n");
208 break;
209 }
210 }
211
212 phy_idx = phy_lookup_idx(phy);
213 if (phy_idx < 0 || phy_idx > UCHAR_MAX) {
214 fprintf(stderr, "Could not find phy '%s'\n", phy);
215 free(an);
216 return 2;
217 }
218
219 if (cmd) {
220 atenl_eeprom_cmd_handler(an, phy_idx, cmd);
221 goto out;
222 }
223
224 atenl_enable = true;
225 atenl_init_signals();
226
227 /* background ourself */
228 if (!fork()) {
229 pid_t pid;
230
231 ret = atenl_eeprom_init(an, phy_idx);
232 if (ret)
233 goto out;
234
235 ret = atenl_eth_init(an);
236 if (ret)
237 goto out;
238
239 ret = pipe(an->pipefd);
240 if (ret) {
241 perror("Pipe");
242 goto out;
243 }
244
245 pid = fork();
246 an->child_pid = pid;
247 if (pid < 0) {
248 perror("Fork");
249 ret = pid;
250 goto out;
251 } else if (pid == 0) {
252 close(an->pipefd[PIPE_WRITE]);
253 atenl_child_work(an);
254 } else {
255 int status;
256
257 close(an->pipefd[PIPE_READ]);
258 atenl_parent_work(an);
259 waitpid(pid, &status, 0);
260 }
261 } else {
262 usleep(800000);
263 }
264
265 ret = 0;
266out:
267 if (an->sock_eth)
268 close(an->sock_eth);
269 if (an->eeprom_fd || an->eeprom_data)
270 atenl_eeprom_close(an);
271 free(an);
272
273 return ret;
274}