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