1 /*
2  * Copyright (c) 2016 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <logging/log.h>
8 LOG_MODULE_REGISTER(net_ieee802154_csma, CONFIG_NET_L2_IEEE802154_LOG_LEVEL);
9 
10 #include <net/net_core.h>
11 #include <net/net_if.h>
12 
13 #include <sys/util.h>
14 #include <random/rand32.h>
15 
16 #include <stdlib.h>
17 #include <errno.h>
18 
19 #include "ieee802154_frame.h"
20 #include "ieee802154_utils.h"
21 #include "ieee802154_radio_utils.h"
22 
csma_ca_radio_send(struct net_if * iface,struct net_pkt * pkt,struct net_buf * frag)23 static inline int csma_ca_radio_send(struct net_if *iface,
24 				     struct net_pkt *pkt,
25 				     struct net_buf *frag)
26 {
27 	const uint8_t max_bo = CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BO;
28 	const uint8_t max_be = CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MAX_BE;
29 	uint8_t retries = CONFIG_NET_L2_IEEE802154_RADIO_TX_RETRIES;
30 	struct ieee802154_context *ctx = net_if_l2_data(iface);
31 	bool ack_required = prepare_for_ack(ctx, pkt, frag);
32 	uint8_t be = CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA_MIN_BE;
33 	uint8_t nb = 0U;
34 	int ret = -EIO;
35 
36 	NET_DBG("frag %p", frag);
37 
38 loop:
39 	while (retries) {
40 		retries--;
41 
42 		if (be) {
43 			uint8_t bo_n = sys_rand32_get() & ((1 << be) - 1);
44 
45 			k_busy_wait(bo_n * 20U);
46 		}
47 
48 		while (1) {
49 			if (!ieee802154_cca(iface)) {
50 				break;
51 			}
52 
53 			be = MIN(be + 1, max_be);
54 			nb++;
55 
56 			if (nb > max_bo) {
57 				goto loop;
58 			}
59 		}
60 
61 		ret = ieee802154_tx(iface, IEEE802154_TX_MODE_DIRECT,
62 				    pkt, frag);
63 		if (ret) {
64 			continue;
65 		}
66 
67 		ret = wait_for_ack(iface, ack_required);
68 		if (!ret) {
69 			break;
70 		}
71 	}
72 
73 	return ret;
74 }
75 
csma_ca_radio_handle_ack(struct net_if * iface,struct net_pkt * pkt)76 static enum net_verdict csma_ca_radio_handle_ack(struct net_if *iface,
77 						 struct net_pkt *pkt)
78 {
79 	struct ieee802154_context *ctx = net_if_l2_data(iface);
80 
81 	if (IS_ENABLED(CONFIG_NET_L2_IEEE802154_RADIO_CSMA_CA) &&
82 	    ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_CSMA) {
83 		return NET_OK;
84 	}
85 
86 	return handle_ack(ctx, pkt);
87 }
88 
89 /* Declare the public Radio driver function used by the HW drivers */
90 FUNC_ALIAS(csma_ca_radio_send,
91 	   ieee802154_radio_send, int);
92 
93 FUNC_ALIAS(csma_ca_radio_handle_ack,
94 	   ieee802154_radio_handle_ack, enum net_verdict);
95