xref: /wlan-driver/qca-wifi-host-cmn/qdf/linux/src/qdf_pkt_add_timestamp.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
3*5113495bSYour Name  *
4*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
5*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
6*5113495bSYour Name  * above copyright notice and this permission notice appear in all
7*5113495bSYour Name  * copies.
8*5113495bSYour Name  *
9*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
17*5113495bSYour Name  */
18*5113495bSYour Name 
19*5113495bSYour Name #include <qdf_pkt_add_timestamp.h>
20*5113495bSYour Name 
21*5113495bSYour Name static struct dp_pkt_add_ts_info dp_pkt_ts_info;
22*5113495bSYour Name static int dp_pkt_add_timestamp;
23*5113495bSYour Name 
qdf_set_dp_pkt_add_ts_info(enum qdf_pkt_supported_proto proto,uint16_t port,uint16_t offset)24*5113495bSYour Name int qdf_set_dp_pkt_add_ts_info(enum qdf_pkt_supported_proto proto,
25*5113495bSYour Name 			       uint16_t port, uint16_t offset)
26*5113495bSYour Name {
27*5113495bSYour Name 	if (dp_pkt_ts_info.current_index >= NUM_DP_PKT_TIMESTAMP_SUPPORT) {
28*5113495bSYour Name 		qdf_err("Only %d number of protocol supported",
29*5113495bSYour Name 			NUM_DP_PKT_TIMESTAMP_SUPPORT);
30*5113495bSYour Name 		return -EINVAL;
31*5113495bSYour Name 	}
32*5113495bSYour Name 
33*5113495bSYour Name 	dp_pkt_ts_info.enable_protocol_bitmap |= (1 << proto);
34*5113495bSYour Name 	dp_pkt_ts_info.proto_info[dp_pkt_ts_info.current_index].proto = proto;
35*5113495bSYour Name 	dp_pkt_ts_info.proto_info[dp_pkt_ts_info.current_index].port = port;
36*5113495bSYour Name 	dp_pkt_ts_info.proto_info[dp_pkt_ts_info.current_index++].offset =
37*5113495bSYour Name 									offset;
38*5113495bSYour Name 	dp_pkt_add_timestamp = 1;
39*5113495bSYour Name 	return 0;
40*5113495bSYour Name }
41*5113495bSYour Name 
qdf_clear_dp_pkt_add_ts_info(void)42*5113495bSYour Name void qdf_clear_dp_pkt_add_ts_info(void)
43*5113495bSYour Name {
44*5113495bSYour Name 	dp_pkt_add_timestamp = 0;
45*5113495bSYour Name 	qdf_mem_zero(&dp_pkt_ts_info, sizeof(dp_pkt_ts_info));
46*5113495bSYour Name }
47*5113495bSYour Name 
48*5113495bSYour Name static
qdf_get_proto_str(enum qdf_pkt_supported_proto proto)49*5113495bSYour Name const char *qdf_get_proto_str(enum qdf_pkt_supported_proto proto)
50*5113495bSYour Name {
51*5113495bSYour Name 	switch (proto) {
52*5113495bSYour Name 	case QDF_PKT_PROTO_TCP:
53*5113495bSYour Name 		return "TCP";
54*5113495bSYour Name 	case QDF_PKT_PROTO_UDP:
55*5113495bSYour Name 		return "UDP";
56*5113495bSYour Name 	default:
57*5113495bSYour Name 		return "Invalid";
58*5113495bSYour Name 	}
59*5113495bSYour Name }
60*5113495bSYour Name 
qdf_show_dp_pkt_add_ts_info(char * buf,size_t size)61*5113495bSYour Name int qdf_show_dp_pkt_add_ts_info(char *buf, size_t size)
62*5113495bSYour Name {
63*5113495bSYour Name 	int i;
64*5113495bSYour Name 	int cnt = 0;
65*5113495bSYour Name 
66*5113495bSYour Name 	qdf_debug("dp_pkt_add_timestamp %d", dp_pkt_add_timestamp);
67*5113495bSYour Name 	qdf_debug("enable_protocol_bitmap %x",
68*5113495bSYour Name 		  dp_pkt_ts_info.enable_protocol_bitmap);
69*5113495bSYour Name 	qdf_debug("current_index %d", dp_pkt_ts_info.current_index);
70*5113495bSYour Name 
71*5113495bSYour Name 	cnt += scnprintf(buf + cnt, size - cnt, "dp_pkt_add_timestamp %d\n",
72*5113495bSYour Name 			 dp_pkt_add_timestamp);
73*5113495bSYour Name 	for (i = 0; i < dp_pkt_ts_info.current_index; i++) {
74*5113495bSYour Name 		qdf_debug("proto %d port %d offset %d",
75*5113495bSYour Name 			  dp_pkt_ts_info.proto_info[i].proto,
76*5113495bSYour Name 			  dp_pkt_ts_info.proto_info[i].port,
77*5113495bSYour Name 			  dp_pkt_ts_info.proto_info[i].offset);
78*5113495bSYour Name 		if (size - cnt <= 0)
79*5113495bSYour Name 			continue;
80*5113495bSYour Name 		cnt += scnprintf(buf + cnt, size - cnt,
81*5113495bSYour Name 				 "Protocol: %s Destination Port %d Offset %d\n",
82*5113495bSYour Name 				 qdf_get_proto_str(
83*5113495bSYour Name 					 dp_pkt_ts_info.proto_info[i].proto),
84*5113495bSYour Name 				 dp_pkt_ts_info.proto_info[i].port,
85*5113495bSYour Name 				 dp_pkt_ts_info.proto_info[i].offset);
86*5113495bSYour Name 	}
87*5113495bSYour Name 	return cnt;
88*5113495bSYour Name }
89*5113495bSYour Name 
qdf_is_dp_pkt_timestamp_enabled(void)90*5113495bSYour Name bool qdf_is_dp_pkt_timestamp_enabled(void)
91*5113495bSYour Name {
92*5113495bSYour Name 	return dp_pkt_add_timestamp;
93*5113495bSYour Name }
94*5113495bSYour Name 
95*5113495bSYour Name static inline
qdf_get_tcp_offset(qdf_nbuf_t nbuf,uint16_t offset)96*5113495bSYour Name uint32_t qdf_get_tcp_offset(qdf_nbuf_t nbuf, uint16_t offset)
97*5113495bSYour Name {
98*5113495bSYour Name 	uint16_t ip_header_len, tcp_header_len, tcp_header_off;
99*5113495bSYour Name 	uint8_t *skb_data = (uint8_t *)qdf_nbuf_data(nbuf);
100*5113495bSYour Name 
101*5113495bSYour Name 	ip_header_len = ((uint8_t)(*(uint8_t *)
102*5113495bSYour Name 				(skb_data + QDF_NBUF_TRAC_IPV4_OFFSET)) &
103*5113495bSYour Name 			QDF_NBUF_TRAC_IPV4_HEADER_MASK) << 2;
104*5113495bSYour Name 	tcp_header_off = QDF_NBUF_TRAC_IPV4_OFFSET + ip_header_len;
105*5113495bSYour Name 	tcp_header_len = ((uint8_t)(*(uint8_t *)
106*5113495bSYour Name 				(skb_data + tcp_header_off +
107*5113495bSYour Name 				 QDF_NBUF_TRAC_TCP_HEADER_LEN_OFFSET))) >> 2;
108*5113495bSYour Name 	return tcp_header_off + tcp_header_len + offset;
109*5113495bSYour Name }
110*5113495bSYour Name 
111*5113495bSYour Name static inline
qdf_get_udp_offset(qdf_nbuf_t nbuf,uint16_t offset)112*5113495bSYour Name uint32_t qdf_get_udp_offset(qdf_nbuf_t nbuf, uint16_t offset)
113*5113495bSYour Name {
114*5113495bSYour Name 	uint16_t ip_header_len, udp_header_len;
115*5113495bSYour Name 	uint8_t *skb_data = (uint8_t *)qdf_nbuf_data(nbuf);
116*5113495bSYour Name 
117*5113495bSYour Name 	ip_header_len = ((uint8_t)(*(uint8_t *)
118*5113495bSYour Name 				(skb_data + QDF_NBUF_TRAC_IPV4_OFFSET)) &
119*5113495bSYour Name 			QDF_NBUF_TRAC_IPV4_HEADER_MASK) << 2;
120*5113495bSYour Name 	udp_header_len = 8;
121*5113495bSYour Name 	return  QDF_NBUF_TRAC_IPV4_OFFSET + ip_header_len +
122*5113495bSYour Name 		udp_header_len + offset;
123*5113495bSYour Name }
124*5113495bSYour Name 
125*5113495bSYour Name static inline
qdf_add_ts(qdf_nbuf_t nbuf,uint32_t offset,enum qdf_pkt_timestamp_index index,uint64_t time,enum qdf_pkt_supported_proto proto)126*5113495bSYour Name void qdf_add_ts(qdf_nbuf_t nbuf, uint32_t offset,
127*5113495bSYour Name 		enum qdf_pkt_timestamp_index index, uint64_t time,
128*5113495bSYour Name 		enum qdf_pkt_supported_proto proto)
129*5113495bSYour Name {
130*5113495bSYour Name 	struct ts *ts_ptr;
131*5113495bSYour Name 	struct ts_info *ts_info;
132*5113495bSYour Name 	uint32_t total_offset;
133*5113495bSYour Name 
134*5113495bSYour Name 	if (proto == QDF_PKT_PROTO_TCP)
135*5113495bSYour Name 		total_offset = qdf_get_tcp_offset(nbuf, offset);
136*5113495bSYour Name 	else if (proto == QDF_PKT_PROTO_UDP)
137*5113495bSYour Name 		total_offset = qdf_get_udp_offset(nbuf, offset);
138*5113495bSYour Name 	else
139*5113495bSYour Name 		return;
140*5113495bSYour Name 
141*5113495bSYour Name 	if (qdf_nbuf_len(nbuf) < total_offset + sizeof(struct ts))
142*5113495bSYour Name 		return;
143*5113495bSYour Name 
144*5113495bSYour Name 	ts_ptr = (struct ts *)(qdf_nbuf_data(nbuf) + total_offset);
145*5113495bSYour Name 	ts_info = &ts_ptr->ts_info[index];
146*5113495bSYour Name 
147*5113495bSYour Name 	ts_info->sec = time / 1000000;
148*5113495bSYour Name 	ts_info->usec = time % 1000000;
149*5113495bSYour Name }
150*5113495bSYour Name 
qdf_add_dp_pkt_timestamp(qdf_nbuf_t nbuf,enum qdf_pkt_timestamp_index index,uint64_t time)151*5113495bSYour Name void qdf_add_dp_pkt_timestamp(qdf_nbuf_t nbuf,
152*5113495bSYour Name 			      enum qdf_pkt_timestamp_index index, uint64_t time)
153*5113495bSYour Name {
154*5113495bSYour Name 	int i;
155*5113495bSYour Name 	uint16_t port;
156*5113495bSYour Name 	uint32_t offset;
157*5113495bSYour Name 
158*5113495bSYour Name 	if (dp_pkt_ts_info.enable_protocol_bitmap & QDF_PKT_PROTO_TCP_BIT) {
159*5113495bSYour Name 		if (qdf_nbuf_is_ipv4_tcp_pkt(nbuf)) {
160*5113495bSYour Name 			port =
161*5113495bSYour Name 			    QDF_SWAP_U16(qdf_nbuf_data_get_tcp_dst_port(nbuf));
162*5113495bSYour Name 			for (i = 0; i < dp_pkt_ts_info.current_index; i++) {
163*5113495bSYour Name 				offset =  dp_pkt_ts_info.proto_info[i].offset;
164*5113495bSYour Name 				if (dp_pkt_ts_info.proto_info[i].proto ==
165*5113495bSYour Name 				    QDF_PKT_PROTO_TCP &&
166*5113495bSYour Name 				    dp_pkt_ts_info.proto_info[i].port == port) {
167*5113495bSYour Name 					qdf_add_ts(nbuf, offset, index, time,
168*5113495bSYour Name 						   QDF_PKT_PROTO_TCP);
169*5113495bSYour Name 					break;
170*5113495bSYour Name 				}
171*5113495bSYour Name 			}
172*5113495bSYour Name 			return;
173*5113495bSYour Name 		}
174*5113495bSYour Name 	}
175*5113495bSYour Name 
176*5113495bSYour Name 	if (dp_pkt_ts_info.enable_protocol_bitmap & QDF_PKT_PROTO_UDP_BIT) {
177*5113495bSYour Name 		if (qdf_nbuf_is_ipv4_udp_pkt(nbuf)) {
178*5113495bSYour Name 			port =
179*5113495bSYour Name 			    QDF_SWAP_U16(qdf_nbuf_data_get_tcp_dst_port(nbuf));
180*5113495bSYour Name 			for (i = 0; i < dp_pkt_ts_info.current_index; i++) {
181*5113495bSYour Name 				offset =  dp_pkt_ts_info.proto_info[i].offset;
182*5113495bSYour Name 				if (dp_pkt_ts_info.proto_info[i].proto ==
183*5113495bSYour Name 				    QDF_PKT_PROTO_UDP &&
184*5113495bSYour Name 				    dp_pkt_ts_info.proto_info[i].port == port) {
185*5113495bSYour Name 					qdf_add_ts(nbuf, offset, index, time,
186*5113495bSYour Name 						   QDF_PKT_PROTO_UDP);
187*5113495bSYour Name 					break;
188*5113495bSYour Name 				}
189*5113495bSYour Name 			}
190*5113495bSYour Name 			return;
191*5113495bSYour Name 		}
192*5113495bSYour Name 	}
193*5113495bSYour Name }
194