1 /** @file
2  * @brief Promiscuous mode support
3  *
4  * Allow user to receive all network packets that are seen by a
5  * network interface. This requires that network device driver
6  * supports promiscuous mode.
7  */
8 
9 /*
10  * Copyright (c) 2018 Intel Corporation
11  *
12  * SPDX-License-Identifier: Apache-2.0
13  */
14 
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(net_promisc, CONFIG_NET_PROMISC_LOG_LEVEL);
17 
18 #include <zephyr/kernel.h>
19 #include <errno.h>
20 
21 #include <zephyr/net/net_if.h>
22 #include <zephyr/net/net_core.h>
23 #include <zephyr/net/net_pkt.h>
24 
25 static K_FIFO_DEFINE(promiscuous_queue);
26 static atomic_t enabled = ATOMIC_INIT(0);
27 
net_promisc_mode_wait_data(k_timeout_t timeout)28 struct net_pkt *net_promisc_mode_wait_data(k_timeout_t timeout)
29 {
30 	return k_fifo_get(&promiscuous_queue, timeout);
31 }
32 
net_promisc_mode_on(struct net_if * iface)33 int net_promisc_mode_on(struct net_if *iface)
34 {
35 	int ret;
36 
37 	if (!iface) {
38 		return -EINVAL;
39 	}
40 
41 	ret = net_if_set_promisc(iface);
42 	if (!ret) {
43 		atomic_inc(&enabled);
44 	}
45 
46 	return ret;
47 }
48 
flush_queue(void)49 static void flush_queue(void)
50 {
51 	struct net_pkt *pkt;
52 
53 	while (1) {
54 		pkt = k_fifo_get(&promiscuous_queue, K_NO_WAIT);
55 		if (!pkt) {
56 			return;
57 		}
58 
59 		net_pkt_unref(pkt);
60 	}
61 }
62 
net_promisc_mode_off(struct net_if * iface)63 int net_promisc_mode_off(struct net_if *iface)
64 {
65 	atomic_val_t prev;
66 	bool ret;
67 
68 	ret = net_if_is_promisc(iface);
69 	if (ret) {
70 		net_if_unset_promisc(iface);
71 
72 		prev = atomic_dec(&enabled);
73 		if (prev == 1) {
74 			atomic_clear(&enabled);
75 
76 			flush_queue();
77 		}
78 
79 		return 0;
80 	}
81 
82 	return -EALREADY;
83 }
84 
net_promisc_mode_input(struct net_pkt * pkt)85 enum net_verdict net_promisc_mode_input(struct net_pkt *pkt)
86 {
87 	if (!pkt) {
88 		return NET_CONTINUE;
89 	}
90 
91 	if (!atomic_get(&enabled)) {
92 		return NET_DROP;
93 	}
94 
95 	k_fifo_put(&promiscuous_queue, pkt);
96 
97 	return NET_OK;
98 }
99