1 /*
2 * wmediumd, wireless medium simulator for mac80211_hwsim kernel module
3 * Copyright (c) 2011 cozybit Inc.
4 * Copyright (C) 2020 Intel Corporation
5 *
6 * Author: Javier Lopez <[email protected]>
7 * Javier Cardona <[email protected]>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 * 02110-1301, USA.
23 */
24
25 #include <netlink/netlink.h>
26 #include <netlink/genl/genl.h>
27 #include <netlink/genl/ctrl.h>
28 #include <netlink/genl/family.h>
29 #include <assert.h>
30 #include <stdint.h>
31 #include <getopt.h>
32 #include <signal.h>
33 #include <math.h>
34 #include <sys/syslog.h>
35 #include <sys/timerfd.h>
36 #include <errno.h>
37 #include <limits.h>
38 #include <time.h>
39 #include <unistd.h>
40 #include <stdarg.h>
41 #include <endian.h>
42 #include <pthread.h>
43 #include <sys/msg.h>
44 #include <usfstl/loop.h>
45 #include <usfstl/sched.h>
46 #include <usfstl/schedctrl.h>
47 #include <usfstl/vhost.h>
48 #include <usfstl/uds.h>
49
50 #include "wmediumd.h"
51 #include "ieee80211.h"
52 #include "config.h"
53 #include "api.h"
54 #include "pmsr.h"
55 #include "grpc.h"
56
57 USFSTL_SCHEDULER(scheduler);
58
59 static void wmediumd_deliver_frame(struct usfstl_job *job);
60
61 enum {
62 HWSIM_VQ_TX,
63 HWSIM_VQ_RX,
64 HWSIM_NUM_VQS,
65 };
66
stpcpy_safe(char * dst,const char * src)67 static char *stpcpy_safe(char *dst, const char *src) {
68 if (dst == NULL) {
69 return NULL;
70 }
71
72 if (src == NULL) {
73 *dst = '\0';
74 return dst;
75 }
76
77 return stpcpy(dst, src);
78 }
79
strlen_safe(const char * src)80 static int strlen_safe(const char *src) {
81 return src == NULL ? 0 : strlen(src);
82 }
83
div_round(int a,int b)84 static inline int div_round(int a, int b)
85 {
86 return (a + b - 1) / b;
87 }
88
sec_to_ns(time_t sec)89 static inline u64 sec_to_ns(time_t sec)
90 {
91 return sec * 1000 * 1000 * 1000;
92 }
93
ns_to_us(u64 ns)94 static inline u64 ns_to_us(u64 ns)
95 {
96 return ns / 1000L;
97 }
98
ts_to_ns(struct timespec ts)99 static inline u64 ts_to_ns(struct timespec ts)
100 {
101 return sec_to_ns(ts.tv_sec) + ts.tv_nsec;
102 }
103
distance_to_rtt(double distance)104 static inline double distance_to_rtt(double distance)
105 {
106 const long light_speed = 299792458L;
107 return distance / light_speed;
108 }
109
sec_to_ps(double sec)110 static inline double sec_to_ps(double sec)
111 {
112 return sec * 1000 * 1000 * 1000;
113 }
114
meter_to_mm(double meter)115 static inline double meter_to_mm(double meter)
116 {
117 return meter * 1000;
118 }
119
pkt_duration(int len,int rate)120 static inline int pkt_duration(int len, int rate)
121 {
122 /* preamble + signal + t_sym * n_sym, rate in 100 kbps */
123 return 16 + 4 + 4 * div_round((16 + 8 * len + 6) * 10, 4 * rate);
124 }
125
w_logf(struct wmediumd * ctx,u8 level,const char * format,...)126 int w_logf(struct wmediumd *ctx, u8 level, const char *format, ...)
127 {
128 va_list(args);
129 va_start(args, format);
130 if (ctx->log_lvl >= level) {
131 return vprintf(format, args);
132 }
133 return -1;
134 }
135
w_flogf(struct wmediumd * ctx,u8 level,FILE * stream,const char * format,...)136 int w_flogf(struct wmediumd *ctx, u8 level, FILE *stream, const char *format, ...)
137 {
138 va_list(args);
139 va_start(args, format);
140 if (ctx->log_lvl >= level) {
141 return vfprintf(stream, format, args);
142 }
143 return -1;
144 }
145
wqueue_init(struct wqueue * wqueue,int cw_min,int cw_max)146 static void wqueue_init(struct wqueue *wqueue, int cw_min, int cw_max)
147 {
148 INIT_LIST_HEAD(&wqueue->frames);
149 wqueue->cw_min = cw_min;
150 wqueue->cw_max = cw_max;
151 }
152
station_init_queues(struct station * station)153 void station_init_queues(struct station *station)
154 {
155 wqueue_init(&station->queues[IEEE80211_AC_BK], 15, 1023);
156 wqueue_init(&station->queues[IEEE80211_AC_BE], 15, 1023);
157 wqueue_init(&station->queues[IEEE80211_AC_VI], 7, 15);
158 wqueue_init(&station->queues[IEEE80211_AC_VO], 3, 7);
159 }
160
frame_has_a4(struct frame * frame)161 static inline bool frame_has_a4(struct frame *frame)
162 {
163 struct ieee80211_hdr *hdr = (void *)frame->data;
164
165 return (hdr->frame_control[1] & (FCTL_TODS | FCTL_FROMDS)) ==
166 (FCTL_TODS | FCTL_FROMDS);
167 }
168
frame_is_mgmt(struct frame * frame)169 static inline bool frame_is_mgmt(struct frame *frame)
170 {
171 struct ieee80211_hdr *hdr = (void *)frame->data;
172
173 return (hdr->frame_control[0] & FCTL_FTYPE) == FTYPE_MGMT;
174 }
175
frame_is_data(struct frame * frame)176 static inline bool frame_is_data(struct frame *frame)
177 {
178 struct ieee80211_hdr *hdr = (void *)frame->data;
179
180 return (hdr->frame_control[0] & FCTL_FTYPE) == FTYPE_DATA;
181 }
182
frame_is_data_qos(struct frame * frame)183 static inline bool frame_is_data_qos(struct frame *frame)
184 {
185 struct ieee80211_hdr *hdr = (void *)frame->data;
186
187 return (hdr->frame_control[0] & (FCTL_FTYPE | STYPE_QOS_DATA)) ==
188 (FTYPE_DATA | STYPE_QOS_DATA);
189 }
190
frame_is_probe_req(struct frame * frame)191 static inline bool frame_is_probe_req(struct frame *frame)
192 {
193 struct ieee80211_hdr *hdr = (void *)frame->data;
194
195 return (hdr->frame_control[0] & (FCTL_FTYPE | STYPE_PROBE_REQ)) ==
196 (FTYPE_MGMT | STYPE_PROBE_REQ);
197 }
198
frame_has_zero_rates(const struct frame * frame)199 static inline bool frame_has_zero_rates(const struct frame *frame)
200 {
201 for (int i = 0; i < frame->tx_rates_count; i++) {
202 if (frame->tx_rates[i].idx < 0)
203 break;
204
205 if (frame->tx_rates[i].count > 0) {
206 return false;
207 }
208 }
209
210 return true;
211 }
212
fill_tx_rates(struct frame * frame)213 static inline void fill_tx_rates(struct frame *frame)
214 {
215 if (frame->tx_rates_count <= 0) {
216 return;
217 }
218
219 int max_index = get_max_index();
220
221 /* Starting from OFDM rate (See per.c#rateset) */
222 const int basic_rate_start = 4; /* 6 mbps */
223
224 int i;
225 int rate_count = min(max_index - basic_rate_start + 1, frame->tx_rates_count);
226
227 for (i = 0; i < rate_count; i++) {
228 frame->tx_rates[i].idx = basic_rate_start + rate_count - i - 1;
229 frame->tx_rates[i].count = 4;
230 }
231
232 for (; i < frame->tx_rates_count; i++) {
233 frame->tx_rates[i].idx = -1;
234 frame->tx_rates[i].count = 0;
235 }
236 }
237
frame_get_qos_ctl(struct frame * frame)238 static inline u8 *frame_get_qos_ctl(struct frame *frame)
239 {
240 struct ieee80211_hdr *hdr = (void *)frame->data;
241
242 if (frame_has_a4(frame))
243 return (u8 *)hdr + 30;
244 else
245 return (u8 *)hdr + 24;
246 }
247
frame_select_queue_80211(struct frame * frame)248 static enum ieee80211_ac_number frame_select_queue_80211(struct frame *frame)
249 {
250 u8 *p;
251 int priority;
252
253 if (!frame_is_data(frame))
254 return IEEE80211_AC_VO;
255
256 if (!frame_is_data_qos(frame))
257 return IEEE80211_AC_BE;
258
259 p = frame_get_qos_ctl(frame);
260 priority = *p & QOS_CTL_TAG1D_MASK;
261
262 return ieee802_1d_to_ac[priority];
263 }
264
dBm_to_milliwatt(int decibel_intf)265 static double dBm_to_milliwatt(int decibel_intf)
266 {
267 #define INTF_LIMIT (31)
268 int intf_diff = NOISE_LEVEL - decibel_intf;
269
270 if (intf_diff >= INTF_LIMIT)
271 return 0.001;
272
273 if (intf_diff <= -INTF_LIMIT)
274 return 1000.0;
275
276 return pow(10.0, -intf_diff / 10.0);
277 }
278
milliwatt_to_dBm(double value)279 static double milliwatt_to_dBm(double value)
280 {
281 return 10.0 * log10(value);
282 }
283
set_interference_duration(struct wmediumd * ctx,int src_idx,int duration,int signal)284 static int set_interference_duration(struct wmediumd *ctx, int src_idx,
285 int duration, int signal)
286 {
287 int i;
288
289 if (!ctx->intf)
290 return 0;
291
292 if (signal >= CCA_THRESHOLD)
293 return 0;
294
295 for (i = 0; i < ctx->num_stas; i++) {
296 ctx->intf[ctx->num_stas * src_idx + i].duration += duration;
297 // use only latest value
298 ctx->intf[ctx->num_stas * src_idx + i].signal = signal;
299 }
300
301 return 1;
302 }
303
get_signal_offset_by_interference(struct wmediumd * ctx,int src_idx,int dst_idx)304 static int get_signal_offset_by_interference(struct wmediumd *ctx, int src_idx,
305 int dst_idx)
306 {
307 int i;
308 double intf_power;
309
310 if (!ctx->intf)
311 return 0;
312
313 intf_power = 0.0;
314 for (i = 0; i < ctx->num_stas; i++) {
315 if (i == src_idx || i == dst_idx)
316 continue;
317 if (drand48() < ctx->intf[i * ctx->num_stas + dst_idx].prob_col)
318 intf_power += dBm_to_milliwatt(
319 ctx->intf[i * ctx->num_stas + dst_idx].signal);
320 }
321
322 if (intf_power <= 1.0)
323 return 0;
324
325 return (int)(milliwatt_to_dBm(intf_power) + 0.5);
326 }
327
is_multicast_ether_addr(const u8 * addr)328 static bool is_multicast_ether_addr(const u8 *addr)
329 {
330 return 0x01 & addr[0];
331 }
332
get_station_by_addr(struct wmediumd * ctx,u8 * addr)333 static struct station *get_station_by_addr(struct wmediumd *ctx, u8 *addr)
334 {
335 struct station *station;
336
337 list_for_each_entry(station, &ctx->stations, list) {
338 if (memcmp(station->addr, addr, ETH_ALEN) == 0)
339 return station;
340 }
341 return NULL;
342 }
343
station_has_addr(struct station * station,const u8 * addr)344 static bool station_has_addr(struct station *station, const u8 *addr)
345 {
346 unsigned int i;
347
348 if (memcmp(station->addr, addr, ETH_ALEN) == 0)
349 return true;
350
351 for (i = 0; i < station->n_addrs; i++) {
352 if (memcmp(station->addrs[i].addr, addr, ETH_ALEN) == 0)
353 return true;
354 }
355
356 return false;
357 }
358
get_station_by_used_addr(struct wmediumd * ctx,u8 * addr)359 static struct station *get_station_by_used_addr(struct wmediumd *ctx, u8 *addr)
360 {
361 struct station *station;
362
363 list_for_each_entry(station, &ctx->stations, list) {
364 if (station_has_addr(station, addr))
365 return station;
366 }
367 return NULL;
368 }
369
wmediumd_wait_for_client_ack(struct wmediumd * ctx,struct client * client)370 static void wmediumd_wait_for_client_ack(struct wmediumd *ctx,
371 struct client *client)
372 {
373 client->wait_for_ack = true;
374
375 while (client->wait_for_ack)
376 usfstl_loop_wait_and_handle();
377 }
378
379 static void wmediumd_remove_client(struct wmediumd *ctx, struct client *client);
380
wmediumd_notify_frame_start(struct usfstl_job * job)381 static void wmediumd_notify_frame_start(struct usfstl_job *job)
382 {
383 struct frame *frame = container_of(job, struct frame, start_job);
384 struct wmediumd *ctx = job->data;
385 struct client *client, *tmp;
386 struct {
387 struct wmediumd_message_header hdr;
388 struct wmediumd_tx_start start;
389 } __attribute__((packed)) msg = {
390 .hdr.type = WMEDIUMD_MSG_TX_START,
391 .hdr.data_len = sizeof(msg.start),
392 .start.freq = frame->freq,
393 };
394
395 if (ctx->ctrl)
396 usfstl_sched_ctrl_sync_to(ctx->ctrl);
397
398 list_for_each_entry_safe(client, tmp, &ctx->clients, list) {
399 if (!(client->flags & WMEDIUMD_CTL_NOTIFY_TX_START))
400 continue;
401
402 if (client == frame->src)
403 msg.start.cookie = frame->cookie;
404 else
405 msg.start.cookie = 0;
406
407 /* must be API socket since flags cannot otherwise be set */
408 assert(client->type == CLIENT_API_SOCK);
409
410 if (write(client->loop.fd, &msg, sizeof(msg)) < sizeof(msg)) {
411 usfstl_loop_unregister(&client->loop);
412 wmediumd_remove_client(ctx, client);
413 continue;
414 }
415
416 wmediumd_wait_for_client_ack(ctx, client);
417 }
418 }
419
log2pcap(struct wmediumd * ctx,struct frame * frame,uint64_t ts)420 static void log2pcap(struct wmediumd *ctx, struct frame *frame, uint64_t ts)
421 {
422 struct {
423 uint8_t it_version;
424 uint8_t it_pad;
425 uint16_t it_len;
426 uint32_t it_present;
427 struct {
428 uint16_t freq, flags;
429 } channel;
430 uint8_t signal;
431 } __attribute__((packed)) radiotap_hdr = {
432 .it_len = htole16(sizeof(radiotap_hdr)),
433 .it_present = htole32(1 << 3 /* channel */ |
434 1 << 5 /* signal dBm */),
435 .channel.freq = htole16(frame->freq),
436 .signal = frame->signal,
437 };
438 struct {
439 uint32_t type, blocklen, ifidx, ts_hi, ts_lo, caplen, pktlen;
440 } __attribute__((packed)) blockhdr = {
441 .type = 6,
442 .ts_hi = ts / (1ULL << 32),
443 .ts_lo = ts,
444 .caplen = frame->data_len + sizeof(radiotap_hdr),
445 .pktlen = frame->data_len + sizeof(radiotap_hdr),
446 };
447 static const uint8_t pad[3];
448 uint32_t sz, align;
449
450 sz = blockhdr.caplen + sizeof(blockhdr) + sizeof(uint32_t);
451 blockhdr.blocklen = (sz + 3) & ~3;
452 align = blockhdr.blocklen - sz;
453
454 fwrite(&blockhdr, sizeof(blockhdr), 1, ctx->pcap_file);
455 fwrite(&radiotap_hdr, sizeof(radiotap_hdr), 1, ctx->pcap_file);
456 fwrite(frame->data, frame->data_len, 1, ctx->pcap_file);
457 fwrite(pad, align, 1, ctx->pcap_file);
458 fwrite(&blockhdr.blocklen, sizeof(blockhdr.blocklen), 1, ctx->pcap_file);
459 fflush(ctx->pcap_file);
460 }
461
queue_frame(struct wmediumd * ctx,struct station * station,struct frame * frame)462 static void queue_frame(struct wmediumd *ctx, struct station *station,
463 struct frame *frame)
464 {
465 struct ieee80211_hdr *hdr = (void *)frame->data;
466 u8 *dest = hdr->addr1;
467 uint64_t target;
468 struct wqueue *queue;
469 struct frame *tail;
470 struct station *tmpsta, *deststa;
471 int send_time;
472 int cw;
473 double error_prob;
474 bool is_acked = false;
475 bool noack = false;
476 int i, j;
477 int rate_idx;
478 int ac;
479
480 /* TODO configure phy parameters */
481 int slot_time = 9;
482 int sifs = 16;
483 int difs = 2 * slot_time + sifs;
484
485 int retries = 0;
486
487 int ack_time_usec = pkt_duration(14, index_to_rate(0, frame->freq)) +
488 sifs;
489
490 /*
491 * To determine a frame's expiration time, we compute the
492 * number of retries we might have to make due to radio conditions
493 * or contention, and add backoff time accordingly. To that, we
494 * add the expiration time of the previous frame in the queue.
495 */
496
497 ac = frame_select_queue_80211(frame);
498 queue = &station->queues[ac];
499
500 /* try to "send" this frame at each of the rates in the rateset */
501 send_time = 0;
502 cw = queue->cw_min;
503
504 int snr = SNR_DEFAULT;
505
506 if (is_multicast_ether_addr(dest)) {
507 deststa = NULL;
508 } else {
509 deststa = get_station_by_used_addr(ctx, dest);
510 if (deststa) {
511 snr = ctx->get_link_snr(ctx, station, deststa) -
512 get_signal_offset_by_interference(ctx,
513 station->index, deststa->index);
514 snr += ctx->get_fading_signal(ctx);
515 }
516 }
517 frame->signal = snr + NOISE_LEVEL;
518
519 noack = is_multicast_ether_addr(dest);
520
521 /*
522 * TODO(b/211353765) Remove this when fundamenal solution is applied
523 *
524 * Temporary workaround for relaying probe_req frame.
525 */
526 if (frame_is_probe_req(frame) && frame_has_zero_rates(frame)) {
527 fill_tx_rates(frame);
528 }
529
530 double choice = drand48();
531
532 for (i = 0; i < frame->tx_rates_count && !is_acked; i++) {
533
534 rate_idx = frame->tx_rates[i].idx;
535
536 /* no more rates in MRR */
537 if (rate_idx < 0)
538 break;
539
540 error_prob = ctx->get_error_prob(ctx, snr, rate_idx,
541 frame->freq, frame->data_len,
542 station, deststa);
543 for (j = 0; j < frame->tx_rates[i].count; j++) {
544 send_time += difs + pkt_duration(frame->data_len,
545 index_to_rate(rate_idx, frame->freq));
546
547 retries++;
548
549 /* skip ack/backoff/retries for noack frames */
550 if (noack) {
551 is_acked = true;
552 break;
553 }
554
555 /* TODO TXOPs */
556
557 /* backoff */
558 if (j > 0) {
559 send_time += (cw * slot_time) / 2;
560 cw = (cw << 1) + 1;
561 if (cw > queue->cw_max)
562 cw = queue->cw_max;
563 }
564
565 send_time += ack_time_usec;
566
567 if (choice > error_prob) {
568 is_acked = true;
569 break;
570 }
571
572 if (!use_fixed_random_value(ctx))
573 choice = drand48();
574 }
575 }
576
577 if (is_acked) {
578 frame->tx_rates[i-1].count = j + 1;
579 for (; i < frame->tx_rates_count; i++) {
580 frame->tx_rates[i].idx = -1;
581 frame->tx_rates[i].count = -1;
582 }
583 frame->flags |= HWSIM_TX_STAT_ACK;
584 }
585
586 /*
587 * delivery time starts after any equal or higher prio frame
588 * (or now, if none).
589 */
590 target = scheduler.current_time;
591 for (i = 0; i <= ac; i++) {
592 list_for_each_entry(tmpsta, &ctx->stations, list) {
593 tail = list_last_entry_or_null(&tmpsta->queues[i].frames,
594 struct frame, list);
595 if (tail && target < tail->job.start)
596 target = tail->job.start;
597 }
598 }
599
600 if (ctx->pcap_file) {
601 log2pcap(ctx, frame, target);
602
603 if (is_acked && !noack) {
604 struct {
605 struct frame frame;
606 uint16_t fc;
607 uint16_t dur;
608 uint8_t ra[6];
609 } __attribute__((packed, aligned(8))) ack = {
610 .fc = htole16(0xd4),
611 .dur = htole16(ack_time_usec),
612 };
613
614 memcpy(&ack.frame, frame, sizeof(ack.frame));
615 ack.frame.data_len = 10;
616 memcpy(ack.ra, frame->data + 10, 6);
617
618 log2pcap(ctx, &ack.frame,
619 target + send_time - ack_time_usec);
620 }
621 }
622
623 target += send_time;
624
625 frame->duration = send_time;
626 frame->src = station->client;
627
628 if (ctx->need_start_notify) {
629 frame->start_job.start = target - send_time;
630 frame->start_job.callback = wmediumd_notify_frame_start;
631 frame->start_job.data = ctx;
632 frame->start_job.name = "frame-start";
633 usfstl_sched_add_job(&scheduler, &frame->start_job);
634 }
635
636 frame->job.start = target;
637 frame->job.callback = wmediumd_deliver_frame;
638 frame->job.data = ctx;
639 frame->job.name = "frame";
640 usfstl_sched_add_job(&scheduler, &frame->job);
641 list_add_tail(&frame->list, &queue->frames);
642 }
643
wmediumd_send_to_client(struct wmediumd * ctx,struct client * client,struct nl_msg * msg)644 static void wmediumd_send_to_client(struct wmediumd *ctx,
645 struct client *client,
646 struct nl_msg *msg)
647 {
648 struct wmediumd_message_header hdr;
649 size_t len;
650 int ret;
651
652 switch (client->type) {
653 case CLIENT_NETLINK:
654 ret = nl_send_auto_complete(ctx->sock, msg);
655 if (ret < 0)
656 w_logf(ctx, LOG_ERR, "%s: nl_send_auto failed\n", __func__);
657 break;
658 case CLIENT_VHOST_USER:
659 len = nlmsg_total_size(nlmsg_datalen(nlmsg_hdr(msg)));
660 usfstl_vhost_user_dev_notify(client->dev, HWSIM_VQ_RX,
661 (void *)nlmsg_hdr(msg), len);
662 break;
663 case CLIENT_API_SOCK:
664 len = nlmsg_total_size(nlmsg_datalen(nlmsg_hdr(msg)));
665 hdr.type = WMEDIUMD_MSG_NETLINK;
666 hdr.data_len = len;
667
668 if (write(client->loop.fd, &hdr, sizeof(hdr)) < sizeof(hdr))
669 goto disconnect;
670
671 if (write(client->loop.fd, (void *)nlmsg_hdr(msg), len) < len)
672 goto disconnect;
673
674 wmediumd_wait_for_client_ack(ctx, client);
675 break;
676 }
677
678 return;
679
680 disconnect:
681 usfstl_loop_unregister(&client->loop);
682 wmediumd_remove_client(ctx, client);
683 }
684
wmediumd_remove_client(struct wmediumd * ctx,struct client * client)685 static void wmediumd_remove_client(struct wmediumd *ctx, struct client *client)
686 {
687 struct frame *frame, *tmp;
688 struct wqueue *queue;
689 struct station *station;
690 int ac;
691
692 list_for_each_entry(station, &ctx->stations, list) {
693 if (station->client == client)
694 station->client = NULL;
695 }
696
697 list_for_each_entry(station, &ctx->stations, list) {
698 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
699 queue = &station->queues[ac];
700 list_for_each_entry_safe(frame, tmp, &queue->frames,
701 list) {
702 if (frame->src == client) {
703 list_del(&frame->list);
704 usfstl_sched_del_job(&frame->job);
705 free(frame);
706 }
707 }
708 }
709 }
710
711 if (!list_empty(&client->list))
712 list_del(&client->list);
713 list_add(&client->list, &ctx->clients_to_free);
714
715 if (client->flags & WMEDIUMD_CTL_NOTIFY_TX_START)
716 ctx->need_start_notify--;
717
718 client->wait_for_ack = false;
719 }
720
721 /*
722 * Report transmit status to the kernel.
723 */
send_tx_info_frame_nl(struct wmediumd * ctx,struct frame * frame)724 static void send_tx_info_frame_nl(struct wmediumd *ctx, struct frame *frame)
725 {
726 struct nl_msg *msg;
727
728 msg = nlmsg_alloc();
729 if (!msg) {
730 w_logf(ctx, LOG_ERR, "Error allocating new message MSG!\n");
731 return;
732 }
733
734 if (genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, ctx->family_id,
735 0, NLM_F_REQUEST, HWSIM_CMD_TX_INFO_FRAME,
736 VERSION_NR) == NULL) {
737 w_logf(ctx, LOG_ERR, "%s: genlmsg_put failed\n", __func__);
738 goto out;
739 }
740
741 if (nla_put(msg, HWSIM_ATTR_ADDR_TRANSMITTER, ETH_ALEN,
742 frame->sender->hwaddr) ||
743 nla_put_u32(msg, HWSIM_ATTR_FLAGS, frame->flags) ||
744 nla_put_u32(msg, HWSIM_ATTR_SIGNAL, frame->signal) ||
745 nla_put(msg, HWSIM_ATTR_TX_INFO,
746 frame->tx_rates_count * sizeof(struct hwsim_tx_rate),
747 frame->tx_rates) ||
748 nla_put_u64(msg, HWSIM_ATTR_COOKIE, frame->cookie)) {
749 w_logf(ctx, LOG_ERR, "%s: Failed to fill a payload\n", __func__);
750 goto out;
751 }
752
753 if (ctx->ctrl)
754 usfstl_sched_ctrl_sync_to(ctx->ctrl);
755 wmediumd_send_to_client(ctx, frame->src, msg);
756
757 out:
758 nlmsg_free(msg);
759 }
760
761 /*
762 * Send a data frame to the kernel for reception at a specific radio.
763 */
send_cloned_frame_msg(struct wmediumd * ctx,struct client * src,struct station * dst,u8 * data,int data_len,int rate_idx,int signal,int freq,uint64_t cookie)764 static void send_cloned_frame_msg(struct wmediumd *ctx, struct client *src,
765 struct station *dst, u8 *data, int data_len,
766 int rate_idx, int signal, int freq,
767 uint64_t cookie)
768 {
769 struct client *client, *tmp;
770 struct nl_msg *msg, *cmsg = NULL;
771
772 msg = nlmsg_alloc();
773 if (!msg) {
774 w_logf(ctx, LOG_ERR, "Error allocating new message MSG!\n");
775 return;
776 }
777
778 if (genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, ctx->family_id,
779 0, NLM_F_REQUEST, HWSIM_CMD_FRAME,
780 VERSION_NR) == NULL) {
781 w_logf(ctx, LOG_ERR, "%s: genlmsg_put failed\n", __func__);
782 goto out;
783 }
784
785 if (nla_put(msg, HWSIM_ATTR_ADDR_RECEIVER, ETH_ALEN,
786 dst->hwaddr) ||
787 nla_put(msg, HWSIM_ATTR_FRAME, data_len, data) ||
788 nla_put_u32(msg, HWSIM_ATTR_RX_RATE, 7) ||
789 nla_put_u32(msg, HWSIM_ATTR_FREQ, freq) ||
790 nla_put_u32(msg, HWSIM_ATTR_SIGNAL, signal)) {
791 w_logf(ctx, LOG_ERR, "%s: Failed to fill a payload\n", __func__);
792 goto out;
793 }
794
795 w_logf(ctx, LOG_DEBUG, "cloned msg dest " MAC_FMT " (radio: " MAC_FMT ") len %d\n",
796 MAC_ARGS(dst->addr), MAC_ARGS(dst->hwaddr), data_len);
797
798 if (ctx->ctrl)
799 usfstl_sched_ctrl_sync_to(ctx->ctrl);
800
801 list_for_each_entry_safe(client, tmp, &ctx->clients, list) {
802 if (client->flags & WMEDIUMD_CTL_RX_ALL_FRAMES) {
803 if (src == client && !cmsg) {
804 struct nlmsghdr *nlh = nlmsg_hdr(msg);
805
806 cmsg = nlmsg_inherit(nlh);
807 nlmsg_append(cmsg, nlmsg_data(nlh), nlmsg_datalen(nlh), 0);
808 assert(nla_put_u64(cmsg, HWSIM_ATTR_COOKIE, cookie) == 0);
809 }
810 wmediumd_send_to_client(ctx, client,
811 src == client ? cmsg : msg);
812 } else if (!dst->client || dst->client == client) {
813 wmediumd_send_to_client(ctx, client, msg);
814 }
815 }
816
817 out:
818 nlmsg_free(msg);
819 if (cmsg)
820 nlmsg_free(cmsg);
821 }
822
wmediumd_deliver_frame(struct usfstl_job * job)823 static void wmediumd_deliver_frame(struct usfstl_job *job)
824 {
825 struct wmediumd *ctx = job->data;
826 struct frame *frame = container_of(job, struct frame, job);
827 struct ieee80211_hdr *hdr = (void *) frame->data;
828 struct station *station;
829 u8 *dest = hdr->addr1;
830 u8 *src = frame->sender->addr;
831
832 list_del(&frame->list);
833
834 if (frame->flags & HWSIM_TX_STAT_ACK) {
835 /* rx the frame on the dest interface */
836 list_for_each_entry(station, &ctx->stations, list) {
837 if (memcmp(src, station->addr, ETH_ALEN) == 0)
838 continue;
839
840 if (is_multicast_ether_addr(dest) && station->client != NULL) {
841 int snr, rate_idx, signal;
842 double error_prob;
843
844 /*
845 * we may or may not receive this based on
846 * reverse link from sender -- check for
847 * each receiver.
848 */
849 snr = ctx->get_link_snr(ctx, frame->sender,
850 station);
851 snr += ctx->get_fading_signal(ctx);
852 signal = snr + NOISE_LEVEL;
853 if (signal < CCA_THRESHOLD)
854 continue;
855
856 if (set_interference_duration(ctx,
857 frame->sender->index, frame->duration,
858 signal))
859 continue;
860
861 snr -= get_signal_offset_by_interference(ctx,
862 frame->sender->index, station->index);
863 rate_idx = frame->tx_rates[0].idx;
864 error_prob = ctx->get_error_prob(ctx,
865 (double)snr, rate_idx, frame->freq,
866 frame->data_len, frame->sender,
867 station);
868
869 if (drand48() <= error_prob) {
870 w_logf(ctx, LOG_INFO, "Dropped mcast from "
871 MAC_FMT " to " MAC_FMT " at receiver\n",
872 MAC_ARGS(src), MAC_ARGS(station->addr));
873 continue;
874 }
875
876 send_cloned_frame_msg(ctx, frame->sender->client,
877 station,
878 frame->data,
879 frame->data_len,
880 1, signal,
881 frame->freq,
882 frame->cookie);
883
884 } else if (station_has_addr(station, dest)) {
885 if (set_interference_duration(ctx,
886 frame->sender->index, frame->duration,
887 frame->signal))
888 continue;
889
890 send_cloned_frame_msg(ctx, frame->sender->client,
891 station,
892 frame->data,
893 frame->data_len,
894 1, frame->signal,
895 frame->freq,
896 frame->cookie);
897 }
898 }
899 } else
900 set_interference_duration(ctx, frame->sender->index,
901 frame->duration, frame->signal);
902
903 send_tx_info_frame_nl(ctx, frame);
904
905 free(frame);
906 }
907
wmediumd_intf_update(struct usfstl_job * job)908 static void wmediumd_intf_update(struct usfstl_job *job)
909 {
910 struct wmediumd *ctx = job->data;
911 int i, j;
912
913 for (i = 0; i < ctx->num_stas; i++)
914 for (j = 0; j < ctx->num_stas; j++) {
915 if (i == j)
916 continue;
917 // probability is used for next calc
918 ctx->intf[i * ctx->num_stas + j].prob_col =
919 ctx->intf[i * ctx->num_stas + j].duration /
920 (double)10000;
921 ctx->intf[i * ctx->num_stas + j].duration = 0;
922 }
923
924 job->start += 10000;
925 usfstl_sched_add_job(&scheduler, job);
926 }
927
928 static
nl_err_cb(struct sockaddr_nl * nla,struct nlmsgerr * nlerr,void * arg)929 int nl_err_cb(struct sockaddr_nl *nla, struct nlmsgerr *nlerr, void *arg)
930 {
931 struct genlmsghdr *gnlh = nlmsg_data(&nlerr->msg);
932 struct wmediumd *ctx = arg;
933
934 w_flogf(ctx, LOG_ERR, stderr, "nl: cmd %d, seq %d: %s\n", gnlh->cmd,
935 nlerr->msg.nlmsg_seq, strerror(abs(nlerr->error)));
936
937 return NL_SKIP;
938 }
939
send_pmsr_result_ftm(struct nl_msg * msg,struct pmsr_request_ftm * req,struct wmediumd * ctx,struct station * sender,struct station * receiver)940 static int send_pmsr_result_ftm(struct nl_msg *msg,
941 struct pmsr_request_ftm *req,
942 struct wmediumd *ctx,
943 struct station *sender,
944 struct station *receiver)
945 {
946 struct nlattr *ftm;
947 int err;
948
949 ftm = nla_nest_start(msg, NL80211_PMSR_TYPE_FTM);
950 if (!ftm)
951 return -ENOMEM;
952
953 if (!receiver) {
954 err = nla_put_u32(msg, NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON,
955 NL80211_PMSR_FTM_FAILURE_NO_RESPONSE);
956 goto out;
957 }
958
959 double distance =
960 sqrt(pow(sender->x - receiver->x, 2) + pow(sender->y - receiver->y, 2));
961 double distance_in_mm = meter_to_mm(distance);
962 double rtt_in_ps = sec_to_ps(distance_to_rtt(distance));
963 if (distance_in_mm > UINT64_MAX || rtt_in_ps > UINT64_MAX) {
964 w_logf(ctx, LOG_WARNING,
965 "%s: Devices are too far away", __func__);
966 return nla_put_u32(msg, NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON,
967 NL80211_PMSR_FTM_FAILURE_NO_RESPONSE);
968 }
969
970 int rssi = receiver->tx_power -
971 ctx->calc_path_loss(NULL, sender, receiver);
972
973 if (nla_put_u32(msg, NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_ATTEMPTS,
974 req->ftmr_retries) ||
975 nla_put_u32(msg, NL80211_PMSR_FTM_RESP_ATTR_NUM_FTMR_SUCCESSES,
976 req->ftmr_retries) ||
977 nla_put_u8(msg, NL80211_PMSR_FTM_RESP_ATTR_NUM_BURSTS_EXP,
978 req->num_bursts_exp) ||
979 nla_put_u8(msg, NL80211_PMSR_FTM_RESP_ATTR_BURST_DURATION,
980 req->burst_duration) ||
981 nla_put_u8(msg, NL80211_PMSR_FTM_RESP_ATTR_FTMS_PER_BURST,
982 req->ftms_per_burst) ||
983 nla_put_s32(msg, NL80211_PMSR_FTM_RESP_ATTR_RSSI_AVG, rssi) ||
984 nla_put_s32(msg, NL80211_PMSR_FTM_RESP_ATTR_RSSI_SPREAD, 0) ||
985 nla_put_u64(msg, NL80211_PMSR_FTM_RESP_ATTR_RTT_AVG,
986 (uint64_t)rtt_in_ps) ||
987 nla_put_u64(msg, NL80211_PMSR_FTM_RESP_ATTR_RTT_VARIANCE, 0) ||
988 nla_put_u64(msg, NL80211_PMSR_FTM_RESP_ATTR_RTT_SPREAD, 0) ||
989 nla_put_u64(msg, NL80211_PMSR_FTM_RESP_ATTR_DIST_AVG,
990 (uint64_t)distance_in_mm) ||
991 nla_put_u64(msg, NL80211_PMSR_FTM_RESP_ATTR_DIST_VARIANCE, 0) ||
992 nla_put_u64(msg, NL80211_PMSR_FTM_RESP_ATTR_DIST_SPREAD, 0)) {
993 w_logf(ctx, LOG_ERR, "%s: Failed to fill a payload\n", __func__);
994 return -ENOMEM;
995 }
996
997 if (req->request_lci && receiver->lci) {
998 nla_put_string(msg, NL80211_PMSR_FTM_RESP_ATTR_LCI,
999 receiver->lci);
1000 }
1001
1002 if (req->request_civicloc && receiver->civicloc) {
1003 nla_put_string(msg, NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC,
1004 receiver->civicloc);
1005 }
1006
1007 out:
1008 if (ftm)
1009 nla_nest_end(msg, ftm);
1010
1011 return 0;
1012 }
1013
send_pmsr_result_peer(struct nl_msg * msg,struct pmsr_request_peer * req,struct wmediumd * ctx,struct station * sender)1014 static int send_pmsr_result_peer(struct nl_msg *msg,
1015 struct pmsr_request_peer *req,
1016 struct wmediumd *ctx,
1017 struct station *sender)
1018 {
1019 struct nlattr *peer, *resp, *data;
1020 struct station *receiver;
1021 int status;
1022 struct timespec ts;
1023 u64 host_time_ns;
1024 u64 ap_tsf_us;
1025 int err;
1026
1027 peer = nla_nest_start(msg, 1);
1028 if (!peer)
1029 return -ENOMEM;
1030
1031 receiver = get_station_by_addr(ctx, req->addr);
1032 if (receiver)
1033 status = NL80211_PMSR_STATUS_SUCCESS;
1034 else {
1035 w_logf(ctx, LOG_WARNING, "%s: unknown pmsr target " MAC_FMT "\n",
1036 __func__, MAC_ARGS(req->addr));
1037 status = NL80211_PMSR_STATUS_FAILURE;
1038 }
1039
1040 if (clock_gettime(CLOCK_BOOTTIME, &ts)) {
1041 w_logf(ctx, LOG_ERR, "%s: clock_gettime() failed\n", __func__);
1042 return -EINVAL;
1043 }
1044
1045 host_time_ns = ts_to_ns(ts);
1046 ap_tsf_us = ns_to_us(ts_to_ns(ts));
1047
1048 err = nla_put(msg, NL80211_PMSR_PEER_ATTR_ADDR, ETH_ALEN, req->addr);
1049 if (err)
1050 return err;
1051
1052 resp = nla_nest_start(msg, NL80211_PMSR_PEER_ATTR_RESP);
1053 if (!resp)
1054 return -ENOMEM;
1055
1056 if (nla_put_u32(msg, NL80211_PMSR_RESP_ATTR_STATUS, status) ||
1057 nla_put_u64(msg, NL80211_PMSR_RESP_ATTR_HOST_TIME, host_time_ns) ||
1058 nla_put_u64(msg, NL80211_PMSR_RESP_ATTR_AP_TSF, ap_tsf_us) ||
1059 nla_put_flag(msg, NL80211_PMSR_RESP_ATTR_FINAL)) {
1060 w_logf(ctx, LOG_ERR, "%s: Failed to fill a payload\n", __func__);
1061 return -ENOMEM;
1062 }
1063
1064 data = nla_nest_start(msg, NL80211_PMSR_RESP_ATTR_DATA);
1065 if (!data)
1066 return -ENOMEM;
1067
1068 err = send_pmsr_result_ftm(msg, &req->ftm, ctx, sender, receiver);
1069
1070 nla_nest_end(msg, data);
1071 nla_nest_end(msg, resp);
1072 nla_nest_end(msg, peer);
1073
1074 return err;
1075 }
1076
send_pmsr_result(struct pmsr_request * request,struct wmediumd * ctx,struct station * sender,struct client * client)1077 static void send_pmsr_result(struct pmsr_request* request, struct wmediumd *ctx,
1078 struct station *sender, struct client *client)
1079 {
1080 struct nl_msg *msg;
1081 struct nlattr *pmsr, *peers;
1082 struct pmsr_request_peer *peer;
1083 int cnt;
1084 int err;
1085
1086 msg = nlmsg_alloc();
1087 if (!msg) {
1088 w_logf(ctx, LOG_ERR, "%s: nlmsg_alloc failed\n", __func__);
1089 return;
1090 }
1091
1092 if (!genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, ctx->family_id,
1093 0, NLM_F_REQUEST, HWSIM_CMD_REPORT_PMSR, VERSION_NR)) {
1094 w_logf(ctx, LOG_ERR, "%s: genlmsg_put failed\n", __func__);
1095 goto out;
1096 }
1097
1098 err = nla_put(msg, HWSIM_ATTR_ADDR_TRANSMITTER,
1099 ETH_ALEN, sender->hwaddr);
1100
1101 pmsr = nla_nest_start(msg, HWSIM_ATTR_PMSR_RESULT);
1102 if (!pmsr)
1103 goto out;
1104
1105 peers = nla_nest_start(msg, NL80211_PMSR_ATTR_PEERS);
1106 if (!peers)
1107 goto out;
1108
1109 list_for_each_entry(peer, &request->peers, list) {
1110 err = send_pmsr_result_peer(msg, peer, ctx, sender);
1111 if (err) {
1112 w_logf(ctx, LOG_ERR,
1113 "%s: Failed to send pmsr result from " MAC_FMT \
1114 " to " MAC_FMT ". Stopping\n", __func__,
1115 MAC_ARGS(sender->addr),
1116 MAC_ARGS(peer->addr));
1117 break;
1118 }
1119 }
1120
1121 nla_nest_end(msg, peers);
1122 nla_nest_end(msg, pmsr);
1123
1124 wmediumd_send_to_client(ctx, client, msg);
1125
1126 out:
1127 nlmsg_free(msg);
1128 }
1129
process_start_pmsr(struct nlattr * attrs[],struct wmediumd * ctx,struct client * client)1130 static void process_start_pmsr(struct nlattr *attrs[], struct wmediumd *ctx,
1131 struct client *client)
1132 {
1133 u8 *hwaddr;
1134 struct station *sender;
1135
1136 struct pmsr_request request;
1137 struct pmsr_request_peer *peer, *tmp;
1138 int err;
1139
1140 if (!attrs[HWSIM_ATTR_ADDR_TRANSMITTER]) {
1141 w_logf(ctx, LOG_ERR, "%s: Missing sender information\n",
1142 __func__);
1143 }
1144
1145 hwaddr = (u8 *)nla_data(attrs[HWSIM_ATTR_ADDR_TRANSMITTER]);
1146 sender = get_station_by_addr(ctx, hwaddr);
1147 if (!sender) {
1148 w_logf(ctx, LOG_ERR, "%s: Unknown sender " MAC_FMT "\n",
1149 __func__, MAC_ARGS(hwaddr));
1150 return;
1151 }
1152
1153 err = parse_pmsr_request(attrs[HWSIM_ATTR_PMSR_REQUEST], &request);
1154 if (err)
1155 goto out;
1156
1157 send_pmsr_result(&request, ctx, sender, client);
1158
1159 out:
1160 list_for_each_entry_safe(peer, tmp, &request.peers, list) {
1161 list_del(&peer->list);
1162 free(peer);
1163 }
1164 }
1165
1166 /*
1167 * Handle events from the kernel. Process CMD_FRAME events and queue them
1168 * for later delivery with the scheduler.
1169 */
_process_messages(struct nl_msg * msg,struct wmediumd * ctx,struct client * client)1170 static void _process_messages(struct nl_msg *msg,
1171 struct wmediumd *ctx,
1172 struct client *client)
1173 {
1174 struct nlattr *attrs[HWSIM_ATTR_MAX+1];
1175 /* netlink header */
1176 struct nlmsghdr *nlh = nlmsg_hdr(msg);
1177 /* generic netlink header*/
1178 struct genlmsghdr *gnlh = nlmsg_data(nlh);
1179
1180 struct station *sender;
1181 struct frame *frame;
1182 struct ieee80211_hdr *hdr;
1183 u8 *src, *hwaddr, *addr;
1184 void *new_addrs;
1185 unsigned int i;
1186
1187 genlmsg_parse(nlh, 0, attrs, HWSIM_ATTR_MAX, NULL);
1188
1189 switch (gnlh->cmd) {
1190 case HWSIM_CMD_FRAME:
1191 if (attrs[HWSIM_ATTR_ADDR_TRANSMITTER]) {
1192 hwaddr = (u8 *)nla_data(attrs[HWSIM_ATTR_ADDR_TRANSMITTER]);
1193
1194 unsigned int data_len =
1195 nla_len(attrs[HWSIM_ATTR_FRAME]);
1196 char *data = (char *)nla_data(attrs[HWSIM_ATTR_FRAME]);
1197 unsigned int flags =
1198 nla_get_u32(attrs[HWSIM_ATTR_FLAGS]);
1199 unsigned int tx_rates_len =
1200 nla_len(attrs[HWSIM_ATTR_TX_INFO]);
1201 struct hwsim_tx_rate *tx_rates =
1202 (struct hwsim_tx_rate *)
1203 nla_data(attrs[HWSIM_ATTR_TX_INFO]);
1204 u64 cookie = nla_get_u64(attrs[HWSIM_ATTR_COOKIE]);
1205 u32 freq;
1206
1207 freq = attrs[HWSIM_ATTR_FREQ] ?
1208 nla_get_u32(attrs[HWSIM_ATTR_FREQ]) : 2412;
1209
1210 hdr = (struct ieee80211_hdr *)data;
1211 src = hdr->addr2;
1212
1213 if (data_len < 6 + 6 + 4)
1214 return;
1215
1216 sender = get_station_by_addr(ctx, hwaddr);
1217 if (!sender) {
1218 sender = get_station_by_used_addr(ctx, src);
1219 if (!sender) {
1220 w_flogf(ctx, LOG_ERR, stderr,
1221 "Unable to find sender station by src=" MAC_FMT " nor hwaddr=" MAC_FMT "\n",
1222 MAC_ARGS(src), MAC_ARGS(hwaddr));
1223 return;
1224 }
1225 memcpy(sender->hwaddr, hwaddr, ETH_ALEN);
1226 }
1227
1228 if (!sender->client)
1229 sender->client = client;
1230
1231 frame = calloc(1, sizeof(*frame) + data_len);
1232 if (!frame)
1233 return;
1234
1235 memcpy(frame->data, data, data_len);
1236 frame->data_len = data_len;
1237 frame->flags = flags;
1238 frame->cookie = cookie;
1239 frame->freq = freq;
1240 frame->sender = sender;
1241 frame->tx_rates_count =
1242 tx_rates_len / sizeof(struct hwsim_tx_rate);
1243 memcpy(frame->tx_rates, tx_rates,
1244 min(tx_rates_len, sizeof(frame->tx_rates)));
1245 queue_frame(ctx, sender, frame);
1246 }
1247 break;
1248 case HWSIM_CMD_ADD_MAC_ADDR:
1249 if (!attrs[HWSIM_ATTR_ADDR_TRANSMITTER] ||
1250 !attrs[HWSIM_ATTR_ADDR_RECEIVER])
1251 break;
1252 hwaddr = (u8 *)nla_data(attrs[HWSIM_ATTR_ADDR_TRANSMITTER]);
1253 addr = (u8 *)nla_data(attrs[HWSIM_ATTR_ADDR_RECEIVER]);
1254 sender = get_station_by_addr(ctx, hwaddr);
1255 if (!sender)
1256 break;
1257 for (i = 0; i < sender->n_addrs; i++) {
1258 if (memcmp(sender->addrs[i].addr, addr, ETH_ALEN) == 0) {
1259 sender->addrs[i].count += 1;
1260 return;
1261 }
1262 }
1263 new_addrs = realloc(sender->addrs, sizeof(struct addr) * (sender->n_addrs + 1));
1264 if (!new_addrs)
1265 break;
1266 sender->addrs = new_addrs;
1267 sender->addrs[sender->n_addrs].count = 1;
1268 memcpy(sender->addrs[sender->n_addrs].addr, addr, ETH_ALEN);
1269 sender->n_addrs += 1;
1270 break;
1271 case HWSIM_CMD_DEL_MAC_ADDR:
1272 if (!attrs[HWSIM_ATTR_ADDR_TRANSMITTER] ||
1273 !attrs[HWSIM_ATTR_ADDR_RECEIVER])
1274 break;
1275 hwaddr = (u8 *)nla_data(attrs[HWSIM_ATTR_ADDR_TRANSMITTER]);
1276 addr = (u8 *)nla_data(attrs[HWSIM_ATTR_ADDR_RECEIVER]);
1277 sender = get_station_by_addr(ctx, hwaddr);
1278 if (!sender)
1279 break;
1280 for (i = 0; i < sender->n_addrs; i++) {
1281 if (memcmp(sender->addrs[i].addr, addr, ETH_ALEN))
1282 continue;
1283 sender->addrs[i].count -= 1;
1284 if (sender->addrs[i].count <= 0) {
1285 sender->n_addrs -= 1;
1286 memmove(&sender->addrs[i],
1287 &sender->addrs[sender->n_addrs],
1288 sizeof(struct addr));
1289 }
1290 break;
1291 }
1292 break;
1293 case HWSIM_CMD_START_PMSR:
1294 process_start_pmsr(attrs, ctx, client);
1295 break;
1296
1297 case HWSIM_CMD_ABORT_PMSR:
1298 // Do nothing. Too late to abort any PMSR.
1299 break;
1300 }
1301 }
1302
process_messages_cb(struct nl_msg * msg,void * arg)1303 static int process_messages_cb(struct nl_msg *msg, void *arg)
1304 {
1305 struct wmediumd *ctx = arg;
1306
1307 _process_messages(msg, ctx, &ctx->nl_client);
1308 return 0;
1309 }
1310
wmediumd_vu_connected(struct usfstl_vhost_user_dev * dev)1311 static void wmediumd_vu_connected(struct usfstl_vhost_user_dev *dev)
1312 {
1313 struct wmediumd *ctx = dev->server->data;
1314 struct client *client;
1315
1316 client = calloc(1, sizeof(*client));
1317 dev->data = client;
1318 client->type = CLIENT_VHOST_USER;
1319 client->dev = dev;
1320 list_add(&client->list, &ctx->clients);
1321 }
1322
wmediumd_vu_handle(struct usfstl_vhost_user_dev * dev,struct usfstl_vhost_user_buf * buf,unsigned int vring)1323 static void wmediumd_vu_handle(struct usfstl_vhost_user_dev *dev,
1324 struct usfstl_vhost_user_buf *buf,
1325 unsigned int vring)
1326 {
1327 struct nl_msg *nlmsg;
1328 char data[4096];
1329 size_t len;
1330
1331 len = iov_read(data, sizeof(data), buf->out_sg, buf->n_out_sg);
1332
1333 if (!nlmsg_ok((const struct nlmsghdr *)data, len))
1334 return;
1335 nlmsg = nlmsg_convert((struct nlmsghdr *)data);
1336 if (!nlmsg)
1337 return;
1338
1339 _process_messages(nlmsg, dev->server->data, dev->data);
1340
1341 nlmsg_free(nlmsg);
1342 }
1343
wmediumd_vu_disconnected(struct usfstl_vhost_user_dev * dev)1344 static void wmediumd_vu_disconnected(struct usfstl_vhost_user_dev *dev)
1345 {
1346 struct client *client = dev->data;
1347
1348 dev->data = NULL;
1349 wmediumd_remove_client(dev->server->data, client);
1350 }
1351
do_data_transfer(void * cookie)1352 static void *do_data_transfer(void *cookie) {
1353 struct wmediumd *ctx = cookie;
1354 switch (ctx->data_transfer_direction) {
1355 case 0: // save
1356 // No device state to save yet, just close the FD.
1357 close(ctx->data_transfer_fd);
1358 break;
1359 case 1: { // load
1360 // No device state to load yet, just verify it is empty.
1361 uint8_t buf;
1362 int n = read(ctx->data_transfer_fd, &buf, 1);
1363 if (n < 0) {
1364 w_logf(ctx, LOG_ERR, "%s: read failed: %s\n", __func__, strerror(errno));
1365 abort();
1366 }
1367 if (n != 0) {
1368 w_logf(ctx, LOG_ERR, "%s: loaded device state is non-empty. BUG!\n", __func__);
1369 abort();
1370 }
1371 close(ctx->data_transfer_fd);
1372 break;
1373 }
1374 default:
1375 w_logf(ctx, LOG_ERR, "%s: invalid transfer_direction: %d\n", __func__, ctx->data_transfer_direction);
1376 abort();
1377 }
1378 return NULL;
1379 }
1380
wmediumd_vu_start_data_transfer(struct usfstl_vhost_user_dev * dev,uint32_t transfer_direction,int fd)1381 static void wmediumd_vu_start_data_transfer(struct usfstl_vhost_user_dev *dev, uint32_t transfer_direction, int fd) {
1382 struct wmediumd *ctx = dev->server->data;
1383
1384 if (ctx->data_transfer_fd != -1) {
1385 w_logf(ctx, LOG_ERR, "%s: can't start multiple data transfers\n", __func__);
1386 abort();
1387 }
1388
1389 ctx->data_transfer_fd = fd;
1390 ctx->data_transfer_direction = transfer_direction;
1391 if (pthread_create(&ctx->data_transfer_thread, NULL, &do_data_transfer, ctx)) {
1392 w_logf(ctx, LOG_ERR, "%s: pthread_create failed: %s\n", __func__, strerror(errno));
1393 abort();
1394 }
1395 }
wmediumd_vu_check_data_transfer(struct usfstl_vhost_user_dev * dev)1396 static void wmediumd_vu_check_data_transfer(struct usfstl_vhost_user_dev *dev) {
1397 struct wmediumd *ctx = dev->server->data;
1398 if (ctx->data_transfer_fd == -1) {
1399 w_logf(ctx, LOG_ERR, "%s: no active data transfer\n", __func__);
1400 abort();
1401 }
1402 if (pthread_join(ctx->data_transfer_thread, NULL)) {
1403 w_logf(ctx, LOG_ERR, "%s: pthread_join failed: %s\n", __func__, strerror(errno));
1404 abort();
1405 }
1406 ctx->data_transfer_fd = -1;
1407 }
1408
process_set_snr_message(struct wmediumd * ctx,struct wmediumd_set_snr * set_snr)1409 static int process_set_snr_message(struct wmediumd *ctx, struct wmediumd_set_snr *set_snr) {
1410 struct station *node1 = get_station_by_addr(ctx, set_snr->node1_mac);
1411 struct station *node2 = get_station_by_addr(ctx, set_snr->node2_mac);
1412
1413 if (node1 == NULL || node2 == NULL) {
1414 return -1;
1415 }
1416
1417 ctx->snr_matrix[ctx->num_stas * node2->index + node1->index] = set_snr->snr;
1418 ctx->snr_matrix[ctx->num_stas * node1->index + node2->index] = set_snr->snr;
1419
1420 return 0;
1421 }
1422
process_load_config_message(struct wmediumd * ctx,struct wmediumd_load_config * reload_config)1423 static int process_load_config_message(struct wmediumd *ctx,
1424 struct wmediumd_load_config *reload_config) {
1425 char *config_path;
1426 int result = 0;
1427
1428 config_path = reload_config->config_path;
1429
1430 if (validate_config(config_path)) {
1431 clear_config(ctx);
1432 load_config(ctx, config_path, NULL);
1433 } else {
1434 result = -1;
1435 }
1436
1437 return result;
1438 }
1439
process_reload_current_config_message(struct wmediumd * ctx)1440 static int process_reload_current_config_message(struct wmediumd *ctx) {
1441 char *config_path;
1442 int result = 0;
1443
1444 config_path = strdup(ctx->config_path);
1445
1446 if (validate_config(config_path)) {
1447 clear_config(ctx);
1448 load_config(ctx, config_path, NULL);
1449 } else {
1450 result = -1;
1451 }
1452
1453 free(config_path);
1454
1455 return result;
1456 }
1457
process_get_stations_message(struct wmediumd * ctx,ssize_t * response_len,unsigned char ** response_data)1458 static int process_get_stations_message(struct wmediumd *ctx, ssize_t *response_len, unsigned char **response_data) {
1459 struct station *station;
1460 int station_count = 0;
1461 int extra_data_len = 0;
1462
1463 // *reponse_data contains struct wmediumd_station_infos
1464 // and then lci and civiclocs for each station follows afterwards.
1465 list_for_each_entry(station, &ctx->stations, list) {
1466 if (station->client != NULL) {
1467 ++station_count;
1468 extra_data_len += strlen_safe(station->lci) + 1;
1469 extra_data_len += strlen_safe(station->civicloc) + 1;
1470 }
1471 }
1472
1473 int station_len = sizeof(uint32_t) + sizeof(struct wmediumd_station_info) * station_count;
1474 *response_len = station_len + extra_data_len;
1475 *response_data = malloc(*response_len);
1476
1477 if (*response_data == NULL) {
1478 w_logf(ctx, LOG_ERR, "%s: failed allocate response data\n", __func__);
1479 return -1;
1480 }
1481
1482 struct wmediumd_station_infos *station_infos = (struct wmediumd_station_infos *)*response_data;
1483 station_infos->count = station_count;
1484 int station_index = 0;
1485 // Pointer to the memory after structs wmediumd_station_infos
1486 // to write lci and civicloc for each station.
1487 char *extra_data_cursor = (char *)&(station_infos->stations[station_count]);
1488
1489 list_for_each_entry(station, &ctx->stations, list) {
1490 if (station->client != NULL) {
1491 struct wmediumd_station_info *station_info = &station_infos->stations[station_index];
1492 memcpy(station_info->addr, station->addr, ETH_ALEN);
1493 memcpy(station_info->hwaddr, station->hwaddr, ETH_ALEN);
1494
1495 station_info->x = station->x;
1496 station_info->y = station->y;
1497 station_info->lci_offset = extra_data_cursor - (char *)station_info;
1498 extra_data_cursor = stpcpy_safe(extra_data_cursor, station->lci) + 1;
1499 station_info->civicloc_offset = extra_data_cursor - (char *)station_info;
1500 extra_data_cursor = stpcpy_safe(extra_data_cursor, station->civicloc) + 1;
1501 station_info->tx_power = station->tx_power;
1502 station_index++;
1503 }
1504 }
1505
1506 return 0;
1507 }
1508
process_set_position_message(struct wmediumd * ctx,struct wmediumd_set_position * set_position)1509 static int process_set_position_message(struct wmediumd *ctx, struct wmediumd_set_position *set_position) {
1510 struct station *node = get_station_by_addr(ctx, set_position->mac);
1511
1512 if (node == NULL) {
1513 return -1;
1514 }
1515
1516 node->x = set_position->x;
1517 node->y = set_position->y;
1518
1519 calc_path_loss(ctx);
1520
1521 return 0;
1522 }
1523
process_set_tx_power_message(struct wmediumd * ctx,struct wmediumd_set_tx_power * set_tx_power)1524 static int process_set_tx_power_message(struct wmediumd *ctx, struct wmediumd_set_tx_power *set_tx_power) {
1525 struct station *node = get_station_by_addr(ctx, set_tx_power->mac);
1526
1527 if (node == NULL) {
1528 return -1;
1529 }
1530
1531 node->tx_power = set_tx_power->tx_power;
1532
1533 calc_path_loss(ctx);
1534
1535 return 0;
1536 }
1537
process_set_lci_message(struct wmediumd * ctx,struct wmediumd_set_lci * set_lci,size_t data_len)1538 static int process_set_lci_message(struct wmediumd *ctx, struct wmediumd_set_lci *set_lci, size_t data_len) {
1539 struct station *node = get_station_by_addr(ctx, set_lci->mac);
1540
1541 if (node == NULL) {
1542 return -1;
1543 }
1544 int expected_len = data_len - offsetof(struct wmediumd_set_lci, lci) - 1;
1545 if (set_lci->lci[expected_len] != '\0') {
1546 return -1;
1547 }
1548
1549 if (node->lci) {
1550 free(node->lci);
1551 }
1552 node->lci = strdup(set_lci->lci);
1553
1554 return node->lci == NULL ? -1 : 0;
1555 }
1556
process_set_civicloc_message(struct wmediumd * ctx,struct wmediumd_set_civicloc * set_civicloc,size_t data_len)1557 static int process_set_civicloc_message(struct wmediumd *ctx, struct wmediumd_set_civicloc *set_civicloc, size_t data_len) {
1558 struct station *node = get_station_by_addr(ctx, set_civicloc->mac);
1559
1560 if (node == NULL) {
1561 return -1;
1562 }
1563 int expected_len = data_len - offsetof(struct wmediumd_set_civicloc, civicloc) - 1;
1564 if (set_civicloc->civicloc[expected_len] != '\0') {
1565 return -1;
1566 }
1567
1568 if (node->civicloc) {
1569 free(node->civicloc);
1570 }
1571 node->civicloc = strdup(set_civicloc->civicloc);
1572
1573 return node->civicloc == NULL ? -1 : 0;
1574 }
1575
1576 static const struct usfstl_vhost_user_ops wmediumd_vu_ops = {
1577 .connected = wmediumd_vu_connected,
1578 .handle = wmediumd_vu_handle,
1579 .disconnected = wmediumd_vu_disconnected,
1580 .start_data_transfer = wmediumd_vu_start_data_transfer,
1581 .check_data_transfer = wmediumd_vu_check_data_transfer,
1582 };
1583
close_pcapng(struct wmediumd * ctx)1584 static void close_pcapng(struct wmediumd *ctx) {
1585 if (ctx->pcap_file == NULL) {
1586 return;
1587 }
1588
1589 fflush(ctx->pcap_file);
1590 fclose(ctx->pcap_file);
1591
1592 ctx->pcap_file = NULL;
1593 }
1594
1595 static void init_pcapng(struct wmediumd *ctx, const char *filename);
1596
wmediumd_send_grpc_response(int msq_id,long msg_type_response,enum wmediumd_grpc_response_data_type data_type,ssize_t data_size,unsigned char * data_payload)1597 static void wmediumd_send_grpc_response(int msq_id, long msg_type_response, enum wmediumd_grpc_response_data_type data_type, ssize_t data_size, unsigned char *data_payload) {
1598 struct wmediumd_grpc_response_message response_message;
1599 response_message.msg_type_response = msg_type_response;
1600 response_message.data_type = data_type;
1601 response_message.data_size = data_size;
1602 if (data_size > 0) {
1603 memcpy(response_message.data_payload, data_payload, data_size);
1604 }
1605 msgsnd(msq_id, &response_message, MSG_TYPE_RESPONSE_SIZE, 0);
1606 }
1607
wmediumd_grpc_service_handler(struct usfstl_loop_entry * entry)1608 static void wmediumd_grpc_service_handler(struct usfstl_loop_entry *entry) {
1609 struct wmediumd *ctx = entry->data;
1610 ssize_t msg_len;
1611
1612 // Receive event from wmediumd_server
1613 uint64_t evt;
1614 read(entry->fd, &evt, sizeof(evt));
1615
1616 struct wmediumd_grpc_request_message request_message;
1617 msg_len = msgrcv(ctx->msq_id, &request_message, MSG_TYPE_REQUEST_SIZE, MSG_TYPE_REQUEST, IPC_NOWAIT);
1618 if (msg_len != MSG_TYPE_REQUEST_SIZE) {
1619 w_logf(ctx, LOG_ERR, "%s: failed to get request message\n", __func__);
1620 } else {
1621 switch (request_message.data_type) {
1622 case REQUEST_LIST_STATIONS: {
1623 ssize_t size = 0;
1624 unsigned char *payload = NULL;
1625 if (process_get_stations_message(ctx, &size, &payload) < 0) {
1626 w_logf(ctx, LOG_ERR, "%s: failed to execute list_stations\n", __func__);
1627 wmediumd_send_grpc_response(ctx->msq_id, request_message.msg_type_response, RESPONSE_INVALID, 0, NULL);
1628 } else {
1629 wmediumd_send_grpc_response(ctx->msq_id, request_message.msg_type_response, RESPONSE_ACK_LIST_STATIONS, size, payload);
1630 }
1631 break;
1632 }
1633 case REQUEST_LOAD_CONFIG:
1634 if (process_load_config_message(ctx, (struct wmediumd_load_config *)(request_message.data_payload)) < 0) {
1635 w_logf(ctx, LOG_ERR, "%s: failed to execute load_config\n", __func__);
1636 wmediumd_send_grpc_response(ctx->msq_id, request_message.msg_type_response, RESPONSE_INVALID, 0, NULL);
1637 break;
1638 }
1639 wmediumd_send_grpc_response(ctx->msq_id, request_message.msg_type_response, RESPONSE_ACK, 0, NULL);
1640 break;
1641 case REQUEST_RELOAD_CONFIG:
1642 if (process_reload_current_config_message(ctx) < 0) {
1643 w_logf(ctx, LOG_ERR, "%s: failed to execute reload_config\n", __func__);
1644 wmediumd_send_grpc_response(ctx->msq_id, request_message.msg_type_response, RESPONSE_INVALID, 0, NULL);
1645 break;
1646 }
1647 wmediumd_send_grpc_response(ctx->msq_id, request_message.msg_type_response, RESPONSE_ACK, 0, NULL);
1648 break;
1649 case REQUEST_SET_CIVICLOC:
1650 if (process_set_civicloc_message(ctx, (struct wmediumd_set_civicloc *)(request_message.data_payload), request_message.data_size) < 0) {
1651 w_logf(ctx, LOG_ERR, "%s: failed to execute set_civicloc\n", __func__);
1652 wmediumd_send_grpc_response(ctx->msq_id, request_message.msg_type_response, RESPONSE_INVALID, 0, NULL);
1653 break;
1654 }
1655 wmediumd_send_grpc_response(ctx->msq_id, request_message.msg_type_response, RESPONSE_ACK, 0, NULL);
1656 break;
1657 case REQUEST_SET_LCI:
1658 if (process_set_lci_message(ctx, (struct wmediumd_set_lci *)(request_message.data_payload), request_message.data_size) < 0) {
1659 w_logf(ctx, LOG_ERR, "%s: failed to execute set_lci\n", __func__);
1660 wmediumd_send_grpc_response(ctx->msq_id, request_message.msg_type_response, RESPONSE_INVALID, 0, NULL);
1661 break;
1662 }
1663 wmediumd_send_grpc_response(ctx->msq_id, request_message.msg_type_response, RESPONSE_ACK, 0, NULL);
1664 break;
1665 case REQUEST_SET_POSITION:
1666 if (process_set_position_message(ctx, (struct wmediumd_set_position *)(request_message.data_payload)) < 0) {
1667 w_logf(ctx, LOG_ERR, "%s: failed to execute set_position\n", __func__);
1668 wmediumd_send_grpc_response(ctx->msq_id, request_message.msg_type_response, RESPONSE_INVALID, 0, NULL);
1669 break;
1670 }
1671 wmediumd_send_grpc_response(ctx->msq_id, request_message.msg_type_response, RESPONSE_ACK, 0, NULL);
1672 break;
1673 case REQUEST_SET_SNR:
1674 if (process_set_snr_message(ctx, (struct wmediumd_set_snr *)(request_message.data_payload)) < 0) {
1675 w_logf(ctx, LOG_ERR, "%s: failed to execute set_snr\n", __func__);
1676 wmediumd_send_grpc_response(ctx->msq_id, request_message.msg_type_response, RESPONSE_INVALID, 0, NULL);
1677 break;
1678 }
1679 wmediumd_send_grpc_response(ctx->msq_id, request_message.msg_type_response, RESPONSE_ACK, 0, NULL);
1680 break;
1681 case REQUEST_SET_TX_POWER:
1682 if (process_set_tx_power_message(ctx, (struct wmediumd_set_tx_power *)(request_message.data_payload)) < 0) {
1683 w_logf(ctx, LOG_ERR, "%s: failed to execute set_tx_power\n", __func__);
1684 wmediumd_send_grpc_response(ctx->msq_id, request_message.msg_type_response, RESPONSE_INVALID, 0, NULL);
1685 break;
1686 }
1687 wmediumd_send_grpc_response(ctx->msq_id, request_message.msg_type_response, RESPONSE_ACK, 0, NULL);
1688 break;
1689 case REQUEST_START_PCAP:
1690 init_pcapng(ctx, ((struct wmediumd_start_pcap *)(request_message.data_payload))->pcap_path);
1691 wmediumd_send_grpc_response(ctx->msq_id, request_message.msg_type_response, RESPONSE_ACK, 0, NULL);
1692 break;
1693 case REQUEST_STOP_PCAP:
1694 close_pcapng(ctx);
1695 wmediumd_send_grpc_response(ctx->msq_id, request_message.msg_type_response, RESPONSE_ACK, 0, NULL);
1696 break;
1697 default:
1698 w_logf(ctx, LOG_ERR, "%s: unknown request type\n", __func__);
1699 wmediumd_send_grpc_response(ctx->msq_id, request_message.msg_type_response, RESPONSE_INVALID, 0, NULL);
1700 break;
1701 }
1702 }
1703 return;
1704 }
1705
1706 // TODO(273384914): Deprecate messages used in wmediumd_control after
1707 // implementing in wmediumd_grpc_service_handler to be used in the command
1708 // 'cvd env'.
wmediumd_api_handler(struct usfstl_loop_entry * entry)1709 static void wmediumd_api_handler(struct usfstl_loop_entry *entry)
1710 {
1711 struct client *client = container_of(entry, struct client, loop);
1712 struct wmediumd *ctx = entry->data;
1713 struct wmediumd_message_header hdr;
1714 enum wmediumd_message response = WMEDIUMD_MSG_ACK;
1715 struct wmediumd_message_control control = {};
1716 struct nl_msg *nlmsg;
1717 unsigned char *data;
1718 ssize_t response_len = 0;
1719 unsigned char *response_data = NULL;
1720 ssize_t len;
1721
1722 len = read(entry->fd, &hdr, sizeof(hdr));
1723 if (len != sizeof(hdr)) {
1724 if (len > 0) {
1725 // Skipping log if the fd is closed.
1726 w_logf(ctx, LOG_ERR, "%s: failed to read header\n", __func__);
1727 }
1728 goto disconnect;
1729 }
1730
1731 /* safety valve */
1732 if (hdr.data_len > 1024 * 1024) {
1733 w_logf(ctx, LOG_ERR, "%s: too large data\n", __func__);
1734 goto disconnect;
1735 }
1736
1737 data = malloc(hdr.data_len);
1738 if (!data) {
1739 w_logf(ctx, LOG_ERR, "%s: failed to malloc\n", __func__);
1740 goto disconnect;
1741 }
1742
1743 len = read(entry->fd, data, hdr.data_len);
1744 if (len != hdr.data_len) {
1745 w_logf(ctx, LOG_ERR, "%s: failed to read data\n", __func__);
1746 goto disconnect;
1747 }
1748
1749 switch (hdr.type) {
1750 case WMEDIUMD_MSG_REGISTER:
1751 if (!list_empty(&client->list)) {
1752 response = WMEDIUMD_MSG_INVALID;
1753 break;
1754 }
1755 list_add(&client->list, &ctx->clients);
1756 break;
1757 case WMEDIUMD_MSG_UNREGISTER:
1758 if (list_empty(&client->list)) {
1759 response = WMEDIUMD_MSG_INVALID;
1760 break;
1761 }
1762 list_del_init(&client->list);
1763 break;
1764 case WMEDIUMD_MSG_NETLINK:
1765 if (ctx->ctrl)
1766 usfstl_sched_ctrl_sync_from(ctx->ctrl);
1767
1768 if (!nlmsg_ok((const struct nlmsghdr *)data, len)) {
1769 response = WMEDIUMD_MSG_INVALID;
1770 break;
1771 }
1772
1773 nlmsg = nlmsg_convert((struct nlmsghdr *)data);
1774 if (!nlmsg)
1775 break;
1776
1777 _process_messages(nlmsg, ctx, client);
1778
1779 nlmsg_free(nlmsg);
1780 break;
1781 case WMEDIUMD_MSG_SET_CONTROL:
1782 /* copy what we get and understand, leave the rest zeroed */
1783 memcpy(&control, data,
1784 min(sizeof(control), hdr.data_len));
1785
1786 if (client->flags & WMEDIUMD_CTL_NOTIFY_TX_START)
1787 ctx->need_start_notify--;
1788 if (control.flags & WMEDIUMD_CTL_NOTIFY_TX_START)
1789 ctx->need_start_notify++;
1790
1791 client->flags = control.flags;
1792 break;
1793 case WMEDIUMD_MSG_GET_STATIONS:
1794 if (process_get_stations_message(ctx, &response_len, &response_data) < 0) {
1795 response = WMEDIUMD_MSG_INVALID;
1796 }
1797 response = WMEDIUMD_MSG_STATIONS_LIST;
1798 break;
1799 case WMEDIUMD_MSG_SET_SNR:
1800 if (process_set_snr_message(ctx, (struct wmediumd_set_snr *)data) < 0) {
1801 response = WMEDIUMD_MSG_INVALID;
1802 }
1803 break;
1804 case WMEDIUMD_MSG_RELOAD_CONFIG:
1805 if (process_load_config_message(ctx,
1806 (struct wmediumd_load_config *)data) < 0) {
1807 response = WMEDIUMD_MSG_INVALID;
1808 }
1809 break;
1810 case WMEDIUMD_MSG_RELOAD_CURRENT_CONFIG:
1811 if (process_reload_current_config_message(ctx) < 0) {
1812 response = WMEDIUMD_MSG_INVALID;
1813 }
1814 break;
1815 case WMEDIUMD_MSG_START_PCAP:
1816 init_pcapng(ctx, ((struct wmediumd_start_pcap *)data)->pcap_path);
1817 break;
1818 case WMEDIUMD_MSG_STOP_PCAP:
1819 close_pcapng(ctx);
1820 break;
1821 case WMEDIUMD_MSG_SET_POSITION:
1822 if (process_set_position_message(ctx, (struct wmediumd_set_position *)data) < 0) {
1823 response = WMEDIUMD_MSG_INVALID;
1824 }
1825 break;
1826 case WMEDIUMD_MSG_SET_LCI:
1827 if (process_set_lci_message(ctx,
1828 (struct wmediumd_set_lci *)data,
1829 hdr.data_len) < 0) {
1830 response = WMEDIUMD_MSG_INVALID;
1831 }
1832 break;
1833 case WMEDIUMD_MSG_SET_CIVICLOC:
1834 if (process_set_civicloc_message(ctx,
1835 (struct wmediumd_set_civicloc *)data,
1836 hdr.data_len) < 0) {
1837 response = WMEDIUMD_MSG_INVALID;
1838 }
1839 break;
1840 case WMEDIUMD_MSG_ACK:
1841 assert(client->wait_for_ack == true);
1842 assert(hdr.data_len == 0);
1843 client->wait_for_ack = false;
1844 /* don't send a response to a response, of course */
1845 return;
1846 default:
1847 w_logf(ctx, LOG_ERR, "%s: unknown message\n", __func__);
1848 response = WMEDIUMD_MSG_INVALID;
1849 break;
1850 }
1851
1852 /* return a response */
1853 hdr.type = response;
1854 hdr.data_len = response_len;
1855 len = write(entry->fd, &hdr, sizeof(hdr));
1856 if (len != sizeof(hdr)) {
1857 w_logf(ctx, LOG_ERR, "%s: failed to write response header\n", __func__);
1858 goto disconnect;
1859 }
1860
1861 if (response_data != NULL) {
1862 if (response_len != 0) {
1863 len = write(entry->fd, response_data, response_len);
1864
1865 if (len != response_len) {
1866 free(response_data);
1867 w_logf(ctx, LOG_ERR, "%s: failed to write response data\n", __func__);
1868 goto disconnect;
1869 }
1870 }
1871
1872 free(response_data);
1873 response_data = NULL;
1874 }
1875
1876 return;
1877 disconnect:
1878 usfstl_loop_unregister(&client->loop);
1879 wmediumd_remove_client(ctx, client);
1880 }
1881
wmediumd_api_connected(int fd,void * data)1882 static void wmediumd_api_connected(int fd, void *data)
1883 {
1884 struct wmediumd *ctx = data;
1885 struct client *client;
1886
1887 client = calloc(1, sizeof(*client));
1888 client->type = CLIENT_API_SOCK;
1889 client->loop.fd = fd;
1890 client->loop.data = ctx;
1891 client->loop.handler = wmediumd_api_handler;
1892 usfstl_loop_register(&client->loop);
1893 INIT_LIST_HEAD(&client->list);
1894 }
1895
1896 /*
1897 * Register with the kernel to start receiving new frames.
1898 */
send_register_msg(struct wmediumd * ctx)1899 static int send_register_msg(struct wmediumd *ctx)
1900 {
1901 struct nl_sock *sock = ctx->sock;
1902 struct nl_msg *msg;
1903 int ret;
1904
1905 msg = nlmsg_alloc();
1906 if (!msg) {
1907 w_logf(ctx, LOG_ERR, "Error allocating new message MSG!\n");
1908 return -1;
1909 }
1910
1911 if (genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, ctx->family_id,
1912 0, NLM_F_REQUEST, HWSIM_CMD_REGISTER,
1913 VERSION_NR) == NULL) {
1914 w_logf(ctx, LOG_ERR, "%s: genlmsg_put failed\n", __func__);
1915 ret = -1;
1916 goto out;
1917 }
1918
1919 ret = nl_send_auto_complete(sock, msg);
1920 if (ret < 0) {
1921 w_logf(ctx, LOG_ERR, "%s: nl_send_auto failed\n", __func__);
1922 ret = -1;
1923 goto out;
1924 }
1925 ret = 0;
1926
1927 out:
1928 nlmsg_free(msg);
1929 return ret;
1930 }
1931
sock_event_cb(struct usfstl_loop_entry * entry)1932 static void sock_event_cb(struct usfstl_loop_entry *entry)
1933 {
1934 struct wmediumd *ctx = entry->data;
1935
1936 nl_recvmsgs_default(ctx->sock);
1937 }
1938
1939 /*
1940 * Setup netlink socket and callbacks.
1941 */
init_netlink(struct wmediumd * ctx)1942 static int init_netlink(struct wmediumd *ctx)
1943 {
1944 struct nl_sock *sock;
1945 int ret;
1946
1947 ctx->cb = nl_cb_alloc(NL_CB_CUSTOM);
1948 if (!ctx->cb) {
1949 w_logf(ctx, LOG_ERR, "Error allocating netlink callbacks\n");
1950 return -1;
1951 }
1952
1953 sock = nl_socket_alloc_cb(ctx->cb);
1954 if (!sock) {
1955 w_logf(ctx, LOG_ERR, "Error allocating netlink socket\n");
1956 return -1;
1957 }
1958
1959 ctx->sock = sock;
1960
1961 ret = genl_connect(sock);
1962 if (ret < 0) {
1963 w_logf(ctx, LOG_ERR, "Error connecting netlink socket ret=%d\n", ret);
1964 return -1;
1965 }
1966
1967 ctx->family_id = genl_ctrl_resolve(sock, "MAC80211_HWSIM");
1968 if (ctx->family_id < 0) {
1969 w_logf(ctx, LOG_ERR, "Family MAC80211_HWSIM not registered\n");
1970 return -1;
1971 }
1972
1973 nl_cb_set(ctx->cb, NL_CB_MSG_IN, NL_CB_CUSTOM, process_messages_cb, ctx);
1974 nl_cb_err(ctx->cb, NL_CB_CUSTOM, nl_err_cb, ctx);
1975
1976 return 0;
1977 }
1978
1979 /*
1980 * Print the CLI help
1981 */
print_help(int exval)1982 static void print_help(int exval)
1983 {
1984 printf("wmediumd v%s - a wireless medium simulator\n", VERSION_STR);
1985 printf("wmediumd [-h] [-V] [-l LOG_LVL] [-x FILE] -c FILE \n\n");
1986
1987 printf(" -h print this help and exit\n");
1988 printf(" -V print version and exit\n\n");
1989
1990 printf(" -l LOG_LVL set the logging level\n");
1991 printf(" LOG_LVL: RFC 5424 severity, values 0 - 7\n");
1992 printf(" >= 3: errors are logged\n");
1993 printf(" >= 5: startup msgs are logged\n");
1994 printf(" >= 6: dropped packets are logged (default)\n");
1995 printf(" == 7: all packets will be logged\n");
1996 printf(" -c FILE set input config file\n");
1997 printf(" -x FILE set input PER file\n");
1998 printf(" -t socket set the time control socket\n");
1999 printf(" -u socket expose vhost-user socket, don't use netlink\n");
2000 printf(" -a socket expose wmediumd API socket\n");
2001 printf(" -n force netlink use even with vhost-user\n");
2002 printf(" -p FILE log packets to pcapng file FILE\n");
2003
2004 exit(exval);
2005 }
2006
init_pcapng(struct wmediumd * ctx,const char * filename)2007 static void init_pcapng(struct wmediumd *ctx, const char *filename)
2008 {
2009 struct {
2010 uint32_t type, blocklen, byte_order;
2011 uint16_t ver_maj, ver_min;
2012 uint64_t seclen;
2013 uint32_t blocklen2;
2014 } __attribute__((packed)) blockhdr = {
2015 .type = 0x0A0D0D0A,
2016 .blocklen = sizeof(blockhdr),
2017 .byte_order = 0x1A2B3C4D,
2018 .ver_maj = 1,
2019 .ver_min = 0,
2020 .seclen = -1,
2021 .blocklen2 = sizeof(blockhdr),
2022 };
2023 struct {
2024 uint32_t type, blocklen;
2025 uint16_t linktype, reserved;
2026 uint32_t snaplen;
2027 struct {
2028 uint16_t code, len;
2029 uint8_t val, pad[3];
2030 } opt_if_tsresol;
2031 struct {
2032 uint16_t code, len;
2033 } opt_endofopt;
2034 uint32_t blocklen2;
2035 } __attribute__((packed)) idb = {
2036 .type = 1,
2037 .blocklen = sizeof(idb),
2038 .linktype = 127, // radiotap
2039 .snaplen = -1,
2040 .opt_if_tsresol.code = 9,
2041 .opt_if_tsresol.len = 1,
2042 .opt_if_tsresol.val = 6, // usec
2043 .blocklen2 = sizeof(idb),
2044 };
2045
2046 if (ctx->pcap_file != NULL) {
2047 close_pcapng(ctx);
2048 }
2049
2050 if (!filename)
2051 return;
2052
2053 ctx->pcap_file = fopen(filename, "w+");
2054 fwrite(&blockhdr, sizeof(blockhdr), 1, ctx->pcap_file);
2055 fwrite(&idb, sizeof(idb), 1, ctx->pcap_file);
2056 }
2057
2058 #ifndef VIRTIO_F_VERSION_1
2059 #define VIRTIO_F_VERSION_1 32
2060 #endif
2061
wmediumd_main(int argc,char * argv[],int event_fd,int msq_id)2062 int wmediumd_main(int argc, char *argv[], int event_fd, int msq_id)
2063 {
2064 int opt;
2065 struct wmediumd ctx = {};
2066 char *config_file = NULL;
2067 char *per_file = NULL;
2068 const char *time_socket = NULL, *api_socket = NULL;
2069 struct usfstl_sched_ctrl ctrl = {};
2070 struct usfstl_vhost_user_server vusrv = {
2071 .ops = &wmediumd_vu_ops,
2072 .max_queues = HWSIM_NUM_VQS,
2073 .input_queues = 1 << HWSIM_VQ_TX,
2074 .features = 1ULL << VIRTIO_F_VERSION_1,
2075 .protocol_features =
2076 1ULL << VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS,
2077 .data = &ctx,
2078 };
2079 bool use_netlink, force_netlink = false;
2080
2081 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
2082
2083 if (argc == 1) {
2084 fprintf(stderr, "This program needs arguments....\n\n");
2085 print_help(EXIT_FAILURE);
2086 }
2087
2088 ctx.log_lvl = 6;
2089 unsigned long int parse_log_lvl;
2090 char* parse_end_token;
2091
2092 while ((opt = getopt(argc, argv, "hVc:l:x:t:u:a:np:")) != -1) {
2093 switch (opt) {
2094 case 'h':
2095 print_help(EXIT_SUCCESS);
2096 break;
2097 case 'V':
2098 printf("wmediumd v%s - a wireless medium simulator "
2099 "for mac80211_hwsim\n", VERSION_STR);
2100 exit(EXIT_SUCCESS);
2101 break;
2102 case 'c':
2103 config_file = optarg;
2104 break;
2105 case 'x':
2106 printf("Input packet error rate file: %s\n", optarg);
2107 per_file = optarg;
2108 break;
2109 case ':':
2110 printf("wmediumd: Error - Option `%c' "
2111 "needs a value\n\n", optopt);
2112 print_help(EXIT_FAILURE);
2113 break;
2114 case 'l':
2115 parse_log_lvl = strtoul(optarg, &parse_end_token, 10);
2116 if ((parse_log_lvl == ULONG_MAX && errno == ERANGE) ||
2117 optarg == parse_end_token || parse_log_lvl > 7) {
2118 printf("wmediumd: Error - Invalid RFC 5424 severity level: "
2119 "%s\n\n", optarg);
2120 print_help(EXIT_FAILURE);
2121 }
2122 ctx.log_lvl = parse_log_lvl;
2123 break;
2124 case 't':
2125 time_socket = optarg;
2126 break;
2127 case 'u':
2128 vusrv.socket = optarg;
2129 break;
2130 case 'a':
2131 api_socket = optarg;
2132 break;
2133 case 'n':
2134 force_netlink = true;
2135 break;
2136 case 'p':
2137 init_pcapng(&ctx, optarg);
2138 break;
2139 case '?':
2140 printf("wmediumd: Error - No such option: "
2141 "`%c'\n\n", optopt);
2142 print_help(EXIT_FAILURE);
2143 break;
2144 }
2145
2146 }
2147
2148 if (optind < argc)
2149 print_help(EXIT_FAILURE);
2150
2151 if (!config_file) {
2152 printf("%s: config file must be supplied\n", argv[0]);
2153 print_help(EXIT_FAILURE);
2154 }
2155
2156 w_logf(&ctx, LOG_NOTICE, "Input configuration file: %s\n", config_file);
2157
2158 INIT_LIST_HEAD(&ctx.stations);
2159 INIT_LIST_HEAD(&ctx.clients);
2160 INIT_LIST_HEAD(&ctx.clients_to_free);
2161
2162 if (load_config(&ctx, config_file, per_file))
2163 return EXIT_FAILURE;
2164
2165 use_netlink = force_netlink || !vusrv.socket;
2166
2167 /* init netlink */
2168 if (use_netlink && init_netlink(&ctx) < 0)
2169 return EXIT_FAILURE;
2170
2171 if (ctx.intf) {
2172 ctx.intf_job.start = 10000; // usec
2173 ctx.intf_job.name = "interference update";
2174 ctx.intf_job.data = &ctx;
2175 ctx.intf_job.callback = wmediumd_intf_update;
2176 usfstl_sched_add_job(&scheduler, &ctx.intf_job);
2177 }
2178
2179 if (vusrv.socket)
2180 usfstl_vhost_user_server_start(&vusrv);
2181
2182 if (use_netlink) {
2183 ctx.nl_client.type = CLIENT_NETLINK;
2184 list_add(&ctx.nl_client.list, &ctx.clients);
2185
2186 ctx.nl_loop.handler = sock_event_cb;
2187 ctx.nl_loop.data = &ctx;
2188 ctx.nl_loop.fd = nl_socket_get_fd(ctx.sock);
2189 usfstl_loop_register(&ctx.nl_loop);
2190
2191 /* register for new frames */
2192 if (send_register_msg(&ctx) == 0)
2193 w_logf(&ctx, LOG_NOTICE, "REGISTER SENT!\n");
2194 }
2195
2196 if (api_socket) {
2197 signal(SIGPIPE, SIG_IGN);
2198 usfstl_uds_create(api_socket, wmediumd_api_connected, &ctx);
2199 }
2200
2201 if (time_socket) {
2202 usfstl_sched_ctrl_start(&ctrl, time_socket,
2203 100,
2204 (uint64_t)-1 /* no ID */,
2205 &scheduler);
2206 vusrv.scheduler = &scheduler;
2207 vusrv.ctrl = &ctrl;
2208 ctx.ctrl = &ctrl;
2209 } else {
2210 usfstl_sched_wallclock_init(&scheduler, 100);
2211 }
2212
2213 // Control event_fd to communicate WmediumdService.
2214 ctx.grpc_loop.handler = wmediumd_grpc_service_handler;
2215 ctx.grpc_loop.data = &ctx;
2216 ctx.grpc_loop.fd = event_fd;
2217 usfstl_loop_register(&ctx.grpc_loop);
2218 ctx.msq_id = msq_id;
2219
2220 ctx.data_transfer_fd = -1;
2221
2222 while (1) {
2223 if (time_socket) {
2224 usfstl_sched_next(&scheduler);
2225 } else {
2226 usfstl_sched_wallclock_wait_and_handle(&scheduler);
2227
2228 if (usfstl_sched_next_pending(&scheduler, NULL))
2229 usfstl_sched_next(&scheduler);
2230 }
2231
2232 while (!list_empty(&ctx.clients_to_free)) {
2233 struct client *client;
2234
2235 client = list_first_entry(&ctx.clients_to_free,
2236 struct client, list);
2237
2238 list_del(&client->list);
2239 free(client);
2240 }
2241 }
2242
2243 free(ctx.sock);
2244 free(ctx.cb);
2245 free(ctx.intf);
2246 free(ctx.per_matrix);
2247
2248 return EXIT_SUCCESS;
2249 }
2250