1 /** @file
2  * @brief UDP packet helpers.
3  */
4 
5 /*
6  * Copyright (c) 2017 Intel Corporation
7  *
8  * SPDX-License-Identifier: Apache-2.0
9  */
10 
11 #include <zephyr/logging/log.h>
12 LOG_MODULE_REGISTER(net_udp, CONFIG_NET_UDP_LOG_LEVEL);
13 
14 #include "net_private.h"
15 #include "udp_internal.h"
16 #include "net_stats.h"
17 
18 #define PKT_WAIT_TIME K_SECONDS(1)
19 
net_udp_create(struct net_pkt * pkt,uint16_t src_port,uint16_t dst_port)20 int net_udp_create(struct net_pkt *pkt, uint16_t src_port, uint16_t dst_port)
21 {
22 	NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr);
23 	struct net_udp_hdr *udp_hdr;
24 
25 	udp_hdr = (struct net_udp_hdr *)net_pkt_get_data(pkt, &udp_access);
26 	if (!udp_hdr) {
27 		return -ENOBUFS;
28 	}
29 
30 	udp_hdr->src_port = src_port;
31 	udp_hdr->dst_port = dst_port;
32 	udp_hdr->len      = 0U;
33 	udp_hdr->chksum   = 0U;
34 
35 	return net_pkt_set_data(pkt, &udp_access);
36 }
37 
net_udp_finalize(struct net_pkt * pkt,bool force_chksum)38 int net_udp_finalize(struct net_pkt *pkt, bool force_chksum)
39 {
40 	NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr);
41 	struct net_udp_hdr *udp_hdr;
42 	uint16_t length = 0;
43 	enum net_if_checksum_type type = net_pkt_family(pkt) == AF_INET6 ?
44 		NET_IF_CHECKSUM_IPV6_UDP : NET_IF_CHECKSUM_IPV4_UDP;
45 
46 	udp_hdr = (struct net_udp_hdr *)net_pkt_get_data(pkt, &udp_access);
47 	if (!udp_hdr) {
48 		return -ENOBUFS;
49 	}
50 
51 	length = net_pkt_get_len(pkt) - net_pkt_ip_hdr_len(pkt) -
52 		 net_pkt_ip_opts_len(pkt);
53 
54 	udp_hdr->len = htons(length);
55 
56 	if (net_if_need_calc_tx_checksum(net_pkt_iface(pkt), type) || force_chksum) {
57 		udp_hdr->chksum = net_calc_chksum_udp(pkt);
58 		net_pkt_set_chksum_done(pkt, true);
59 	}
60 
61 	return net_pkt_set_data(pkt, &udp_access);
62 }
63 
net_udp_get_hdr(struct net_pkt * pkt,struct net_udp_hdr * hdr)64 struct net_udp_hdr *net_udp_get_hdr(struct net_pkt *pkt,
65 				    struct net_udp_hdr *hdr)
66 {
67 	NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(udp_access, struct net_udp_hdr);
68 	struct net_pkt_cursor backup;
69 	struct net_udp_hdr *udp_hdr;
70 	bool overwrite;
71 
72 	udp_access.data = hdr;
73 
74 	overwrite = net_pkt_is_being_overwritten(pkt);
75 	net_pkt_set_overwrite(pkt, true);
76 
77 	net_pkt_cursor_backup(pkt, &backup);
78 	net_pkt_cursor_init(pkt);
79 
80 	if (net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) +
81 			 net_pkt_ip_opts_len(pkt))) {
82 		udp_hdr = NULL;
83 		goto out;
84 	}
85 
86 	udp_hdr = (struct net_udp_hdr *)net_pkt_get_data(pkt, &udp_access);
87 
88 out:
89 	net_pkt_cursor_restore(pkt, &backup);
90 	net_pkt_set_overwrite(pkt, overwrite);
91 
92 	return udp_hdr;
93 }
94 
net_udp_set_hdr(struct net_pkt * pkt,struct net_udp_hdr * hdr)95 struct net_udp_hdr *net_udp_set_hdr(struct net_pkt *pkt,
96 				    struct net_udp_hdr *hdr)
97 {
98 	NET_PKT_DATA_ACCESS_DEFINE(udp_access, struct net_udp_hdr);
99 	struct net_pkt_cursor backup;
100 	struct net_udp_hdr *udp_hdr;
101 	bool overwrite;
102 
103 	overwrite = net_pkt_is_being_overwritten(pkt);
104 	net_pkt_set_overwrite(pkt, true);
105 
106 	net_pkt_cursor_backup(pkt, &backup);
107 	net_pkt_cursor_init(pkt);
108 
109 	if (net_pkt_skip(pkt, net_pkt_ip_hdr_len(pkt) +
110 			 net_pkt_ip_opts_len(pkt))) {
111 		udp_hdr = NULL;
112 		goto out;
113 	}
114 
115 	udp_hdr = (struct net_udp_hdr *)net_pkt_get_data(pkt, &udp_access);
116 	if (!udp_hdr) {
117 		goto out;
118 	}
119 
120 	memcpy(udp_hdr, hdr, sizeof(struct net_udp_hdr));
121 
122 	net_pkt_set_data(pkt, &udp_access);
123 out:
124 	net_pkt_cursor_restore(pkt, &backup);
125 	net_pkt_set_overwrite(pkt, overwrite);
126 
127 	return udp_hdr == NULL ? NULL : hdr;
128 }
129 
net_udp_register(uint8_t family,const struct sockaddr * remote_addr,const struct sockaddr * local_addr,uint16_t remote_port,uint16_t local_port,struct net_context * context,net_conn_cb_t cb,void * user_data,struct net_conn_handle ** handle)130 int net_udp_register(uint8_t family,
131 		     const struct sockaddr *remote_addr,
132 		     const struct sockaddr *local_addr,
133 		     uint16_t remote_port,
134 		     uint16_t local_port,
135 		     struct net_context *context,
136 		     net_conn_cb_t cb,
137 		     void *user_data,
138 		     struct net_conn_handle **handle)
139 {
140 	return net_conn_register(IPPROTO_UDP, family, remote_addr, local_addr,
141 				 remote_port, local_port, context, cb,
142 				 user_data, handle);
143 }
144 
net_udp_unregister(struct net_conn_handle * handle)145 int net_udp_unregister(struct net_conn_handle *handle)
146 {
147 	return net_conn_unregister(handle);
148 }
149 
net_udp_input(struct net_pkt * pkt,struct net_pkt_data_access * udp_access)150 struct net_udp_hdr *net_udp_input(struct net_pkt *pkt,
151 				  struct net_pkt_data_access *udp_access)
152 {
153 	struct net_udp_hdr *udp_hdr;
154 	enum net_if_checksum_type type = net_pkt_family(pkt) == AF_INET6 ?
155 		NET_IF_CHECKSUM_IPV6_UDP : NET_IF_CHECKSUM_IPV4_UDP;
156 
157 	udp_hdr = (struct net_udp_hdr *)net_pkt_get_data(pkt, udp_access);
158 	if (!udp_hdr || net_pkt_set_data(pkt, udp_access)) {
159 		NET_DBG("DROP: corrupted header");
160 		goto drop;
161 	}
162 
163 	if (ntohs(udp_hdr->len) != (net_pkt_get_len(pkt) -
164 				    net_pkt_ip_hdr_len(pkt) -
165 				    net_pkt_ip_opts_len(pkt))) {
166 		NET_DBG("DROP: Invalid hdr length");
167 		goto drop;
168 	}
169 
170 	if (IS_ENABLED(CONFIG_NET_UDP_CHECKSUM) &&
171 	    (net_if_need_calc_rx_checksum(net_pkt_iface(pkt), type) ||
172 	     net_pkt_is_ip_reassembled(pkt))) {
173 		if (!udp_hdr->chksum) {
174 			if (IS_ENABLED(CONFIG_NET_UDP_MISSING_CHECKSUM) &&
175 			    net_pkt_family(pkt) == AF_INET) {
176 				goto out;
177 			}
178 
179 			goto drop;
180 		}
181 
182 		if (net_calc_verify_chksum_udp(pkt) != 0U) {
183 			NET_DBG("DROP: checksum mismatch");
184 			goto drop;
185 		}
186 	}
187 out:
188 	return udp_hdr;
189 drop:
190 	net_stats_update_udp_chkerr(net_pkt_iface(pkt));
191 	return NULL;
192 }
193