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