1 /*
2  * Copyright (c) 2016 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef __IEEE802154_RADIO_UTILS_H__
8 #define __IEEE802154_RADIO_UTILS_H__
9 
10 #include "ieee802154_utils.h"
11 
12 /**
13  * @brief Radio driver sending function that radio drivers should implement
14  *
15  * @param iface A valid pointer on a network interface to send from
16  * @param pkt A valid pointer on a packet to send
17  *
18  * @return 0 on success, negative value otherwise
19  */
20 extern int ieee802154_radio_send(struct net_if *iface,
21 				 struct net_pkt *pkt,
22 				 struct net_buf *frag);
23 
prepare_for_ack(struct ieee802154_context * ctx,struct net_pkt * pkt,struct net_buf * frag)24 static inline bool prepare_for_ack(struct ieee802154_context *ctx,
25 				   struct net_pkt *pkt,
26 				   struct net_buf *frag)
27 {
28 	if (ieee802154_is_ar_flag_set(frag)) {
29 		struct ieee802154_fcf_seq *fs;
30 
31 		fs = (struct ieee802154_fcf_seq *)frag->data;
32 
33 		ctx->ack_seq = fs->sequence;
34 		ctx->ack_received = false;
35 		k_sem_init(&ctx->ack_lock, 0, K_SEM_MAX_LIMIT);
36 
37 		return true;
38 	}
39 
40 	return false;
41 }
42 
wait_for_ack(struct net_if * iface,bool ack_required)43 static inline int wait_for_ack(struct net_if *iface,
44 			       bool ack_required)
45 {
46 	struct ieee802154_context *ctx = net_if_l2_data(iface);
47 
48 
49 	if (!ack_required ||
50 	    (ieee802154_get_hw_capabilities(iface) & IEEE802154_HW_TX_RX_ACK)) {
51 		return 0;
52 	}
53 
54 	if (k_sem_take(&ctx->ack_lock, K_MSEC(10)) == 0) {
55 		/*
56 		 * We reinit the semaphore in case handle_ack
57 		 * got called multiple times.
58 		 */
59 		k_sem_init(&ctx->ack_lock, 0, K_SEM_MAX_LIMIT);
60 	}
61 
62 	ctx->ack_seq = 0U;
63 
64 	return ctx->ack_received ? 0 : -EIO;
65 }
66 
handle_ack(struct ieee802154_context * ctx,struct net_pkt * pkt)67 static inline int handle_ack(struct ieee802154_context *ctx,
68 			     struct net_pkt *pkt)
69 {
70 	if (pkt->buffer->len == IEEE802154_ACK_PKT_LENGTH) {
71 		uint8_t len = IEEE802154_ACK_PKT_LENGTH;
72 		struct ieee802154_fcf_seq *fs;
73 
74 		fs = ieee802154_validate_fc_seq(net_pkt_data(pkt), NULL, &len);
75 		if (!fs || fs->sequence != ctx->ack_seq) {
76 			return NET_CONTINUE;
77 		}
78 
79 		ctx->ack_received = true;
80 		k_sem_give(&ctx->ack_lock);
81 
82 		return NET_OK;
83 	}
84 
85 	return NET_CONTINUE;
86 }
87 
88 #endif /* __IEEE802154_RADIO_UTILS_H__ */
89