1 /* main.c - Application main entry point */
2 
3 /*
4  * Copyright (c) 2016 Intel Corporation
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #include <zephyr/logging/log.h>
10 LOG_MODULE_REGISTER(net_test, CONFIG_NET_DHCPV4_LOG_LEVEL);
11 
12 #include <zephyr/kernel.h>
13 #include <zephyr/linker/sections.h>
14 
15 #include <zephyr/types.h>
16 #include <stddef.h>
17 #include <string.h>
18 #include <stdio.h>
19 #include <errno.h>
20 #include <zephyr/device.h>
21 #include <zephyr/init.h>
22 #include <zephyr/net/net_core.h>
23 #include <zephyr/net/net_pkt.h>
24 #include <zephyr/net/net_ip.h>
25 #include <zephyr/net/dhcpv4.h>
26 #include <zephyr/net/ethernet.h>
27 #include <zephyr/net/net_mgmt.h>
28 #include <zephyr/net/dummy.h>
29 
30 #include "ipv4.h"
31 #include "udp_internal.h"
32 
33 #include <zephyr/tc_util.h>
34 #include <zephyr/ztest.h>
35 
36 #define NET_LOG_ENABLED 1
37 #include "net_private.h"
38 
39 /* Sample DHCP offer (420 bytes) */
40 static const unsigned char offer[] = {
41 0x02, 0x01, 0x06, 0x00, 0x00, 0x00,
42 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
43 0x00, 0x00, 0x0a, 0xed, 0x48, 0x9e, 0x0a, 0xb8,
44 0x09, 0x01, 0x0a, 0xed, 0x48, 0x02, 0x00, 0x00,
45 0x5E, 0x00, 0x53, 0x01, 0x00, 0x00, 0x00, 0x00,
46 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
47 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
55 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
63 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
64 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
66 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71 /* Magic cookie: DHCP */
72 0x63, 0x82, 0x53, 0x63,
73 /* [0] Pad option */
74 0x00,
75 /* [53] DHCP Message Type: OFFER */
76 0x35, 0x01, 0x02,
77 /* [1] Subnet Mask: 255.255.255.0 */
78 0x01, 0x04, 0xff, 0xff, 0xff, 0x00,
79 /* [58] Renewal Time Value: (21600s) 6 hours */
80 0x3a, 0x04, 0x00, 0x00, 0x54, 0x60,
81 /* [59] Rebinding Time Value: (37800s) 1 hour 30 min */
82 0x3b, 0x04, 0x00, 0x00, 0x93, 0xa8,
83 /* [51] IP Address Lease Time: (43200s) 12 hours */
84 0x33, 0x04, 0x00, 0x00, 0xa8, 0xc0,
85 /* [54] DHCP Server Identifier: 10.184.9.1 */
86 0x36, 0x04, 0x0a, 0xb8, 0x09, 0x01,
87 /* [3] Router: 10.237.72.1 */
88 0x03, 0x04, 0x0a, 0xed, 0x48, 0x01,
89 /* [15] Domain Name: fi.intel.com */
90 0x0f, 0x0d, 0x66, 0x69, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x00,
91 /* [6] Domain Name Server: 10.248.2.1 163.33.253.68 10.184.9.1 */
92 0x06, 0x0c, 0x0a, 0xf8, 0x02, 0x01, 0xa3, 0x21, 0xfd, 0x44, 0x0a, 0xb8, 0x09, 0x01,
93 /* [119] Domain Search Option: fi.intel.com ger.corp.intel.com corp.intel.com intel.com */
94 0x77, 0x3d, 0x02, 0x66, 0x69, 0x05, 0x69, 0x6e,
95 0x74, 0x65, 0x6c, 0x03, 0x63, 0x6f, 0x6d, 0x00,
96 0x03, 0x67, 0x65, 0x72, 0x04, 0x63, 0x6f, 0x72,
97 0x70, 0x05, 0x69, 0x6e, 0x74, 0x65, 0x6c, 0x03,
98 0x63, 0x6f, 0x6d, 0x00, 0x04, 0x63, 0x6f, 0x72,
99 0x70, 0x05, 0x69, 0x6e, 0x74, 0x65, 0x6c, 0x03,
100 0x63, 0x6f, 0x6d, 0x00, 0x05, 0x69, 0x6e, 0x74,
101 0x65, 0x6c, 0x03, 0x63, 0x6f, 0x6d, 0x00,
102 /* [44] NetBIOS Name Servers: 163.33.7.86, 143.182.250.105 */
103 0x2c, 0x08, 0xa3, 0x21, 0x07, 0x56, 0x8f, 0xb6, 0xfa, 0x69,
104 /* [43] Encapsulated vendor specific information */
105 0x2b, 0x0a,
106 	    /* [1]: "string" */
107 	    0x01, 0x07, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00,
108 	    /* End marker */
109 	    0xff,
110 /* [43] Encapsulated vendor specific information */
111 0x2b, 0x0f,
112 	    /* [2]: single byte of value 1 */
113 	    0x02, 0x01, 0x01,
114 	    /* [3]: zero-length option */
115 	    0x03, 0x00,
116 	    /* [254]: invalid option (size longer than remainder of opt 43 size) */
117 	    0xfe, 0x10, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
118 /* [43] Too short encapsulated vendor option (only single byte) */
119 0x2b, 0x01,
120 	    /* [254]: invalid option (no length in opt 43) */
121 	    0xfe,
122 /* [70] POP3 Server: 198.51.100.16 */
123 0x46, 0x04, 0xc6, 0x33, 0x64, 0x10,
124 /* End marker */
125 0xff
126 };
127 
128 /* Sample DHCPv4 ACK */
129 static const unsigned char ack[] = {
130 0x02, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132 0x0a, 0xed, 0x48, 0x9e, 0x00, 0x00, 0x00, 0x00,
133 0x0a, 0xed, 0x48, 0x03, 0x00, 0x00, 0x5E, 0x00,
134 0x53, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
136 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
140 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
149 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
150 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
152 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
159 0x00, 0x00, 0x00, 0x00,
160 /* Magic cookie: DHCP */
161 0x63, 0x82, 0x53, 0x63,
162 /* [0] Pad option */
163 0x00,
164 /* [53] DHCP Message Type: ACK */
165 0x35, 0x01, 0x05,
166 /* [58] Renewal Time Value: (21600s) 6 hours */
167 0x3a, 0x04, 0x00, 0x00, 0x54, 0x60,
168 /* [59] Rebinding Time Value: (37800s) 1 hour 30 min */
169 0x3b, 0x04, 0x00, 0x00, 0x93, 0xa8,
170 /* [51] IP Address Lease Time: (43200s) 12 hours */
171 0x33, 0x04, 0x00, 0x00, 0xa8, 0xc0,
172 /* [54] DHCP Server Identifier: 10.184.9.1 */
173 0x36, 0x04, 0x0a, 0xb8, 0x09, 0x01,
174 /* [1] Subnet Mask: 255.255.255.0 */
175 0x01, 0x04, 0xff, 0xff, 0xff, 0x00,
176 /* [3] Router: 10.237.72.1 */
177 0x03, 0x04, 0x0a, 0xed, 0x48, 0x01,
178 /* [15] Domain Name: fi.intel.com */
179 0x0f, 0x0d, 0x66, 0x69, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x00,
180 /* [6] Domain Name Server: 10.248.2.1 163.33.253.68 10.184.9.1 */
181 0x06, 0x0c, 0x0a, 0xf8, 0x02, 0x01, 0xa3, 0x21, 0xfd, 0x44, 0x0a, 0xb8, 0x09, 0x01,
182 /* [119] Domain Search Option: fi.intel.com ger.corp.intel.com corp.intel.com intel.com */
183 0x77, 0x3d, 0x02, 0x66, 0x69, 0x05, 0x69, 0x6e,
184 0x74, 0x65, 0x6c, 0x03, 0x63, 0x6f, 0x6d, 0x00,
185 0x03, 0x67, 0x65, 0x72, 0x04, 0x63, 0x6f, 0x72,
186 0x70, 0x05, 0x69, 0x6e, 0x74, 0x65, 0x6c, 0x03,
187 0x63, 0x6f, 0x6d, 0x00, 0x04, 0x63, 0x6f, 0x72,
188 0x70, 0x05, 0x69, 0x6e, 0x74, 0x65, 0x6c, 0x03,
189 0x63, 0x6f, 0x6d, 0x00, 0x05, 0x69, 0x6e, 0x74,
190 0x65, 0x6c, 0x03, 0x63, 0x6f, 0x6d, 0x00,
191 /* [44] NetBIOS Name Servers: 163.33.7.86, 143.182.250.105 */
192 0x2c, 0x08, 0xa3, 0x21, 0x07, 0x56, 0x8f, 0xb6, 0xfa, 0x69,
193 /* [43] Encapsulated vendor specific information */
194 0x2b, 0x0a,
195 	    /* [1]: "string" */
196 	    0x01, 0x07, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00,
197 	    /* End marker */
198 	    0xff,
199 /* [43] Encapsulated vendor specific information */
200 0x2b, 0x0f,
201 	    /* [2]: single byte of value 1 */
202 	    0x02, 0x01, 0x01,
203 	    /* [3]: zero-length option */
204 	    0x03, 0x00,
205 	    /* [254]: invalid option (size longer than remainder of opt 43 size) */
206 	    0xfe, 0x10, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
207 /* [43] Too short encapsulated vendor option (only single byte) */
208 0x2b, 0x01,
209 	    /* [254]: invalid option (no length in opt 43) */
210 	    0xfe,
211 /* [70] POP3 Server: 198.51.100.16 */
212 0x46, 0x04, 0xc6, 0x33, 0x64, 0x10,
213 /* End marker */
214 0xff
215 };
216 
217 static const struct in_addr server_addr = { { { 192, 0, 2, 1 } } };
218 static const struct in_addr client_addr = { { { 255, 255, 255, 255 } } };
219 
220 #define SERVER_PORT		67
221 #define CLIENT_PORT		68
222 #define MSG_TYPE		53
223 #define DISCOVER		1
224 #define REQUEST			3
225 #define OPTION_DOMAIN		15
226 #define OPTION_POP3		70
227 #define OPTION_VENDOR_STRING	1
228 #define OPTION_VENDOR_BYTE	2
229 #define OPTION_VENDOR_EMPTY	3
230 #define OPTION_INVALID		254
231 
232 struct dhcp_msg {
233 	uint32_t xid;
234 	uint8_t type;
235 };
236 
237 static uint32_t offer_xid;
238 static uint32_t request_xid;
239 
240 #define EVT_ADDR_ADD        BIT(0)
241 #define EVT_ADDR_DEL        BIT(1)
242 #define EVT_DNS_SERVER1_ADD BIT(2)
243 #define EVT_DNS_SERVER2_ADD BIT(3)
244 #define EVT_DNS_SERVER3_ADD BIT(4)
245 #define EVT_DHCP_START      BIT(5)
246 #define EVT_DHCP_BOUND      BIT(6)
247 #define EVT_DHCP_STOP       BIT(7)
248 #define EVT_OPTION_DOMAIN   BIT(8)
249 #define EVT_OPTION_POP3     BIT(9)
250 #define EVT_VENDOR_STRING   BIT(10)
251 #define EVT_VENDOR_BYTE     BIT(11)
252 #define EVT_VENDOR_EMPTY    BIT(12)
253 #define EVT_DHCP_OFFER      BIT(13)
254 #define EVT_DHCP_ACK        BIT(14)
255 #define EVT_DNS_SERVER1_DEL BIT(15)
256 #define EVT_DNS_SERVER2_DEL BIT(16)
257 #define EVT_DNS_SERVER3_DEL BIT(17)
258 
259 static K_EVENT_DEFINE(events);
260 
261 #define WAIT_TIME K_SECONDS(CONFIG_NET_DHCPV4_INITIAL_DELAY_MAX + 1)
262 
263 struct net_dhcpv4_context {
264 	uint8_t mac_addr[sizeof(struct net_eth_addr)];
265 	struct net_linkaddr ll_addr;
266 };
267 
net_dhcpv4_dev_init(const struct device * dev)268 static int net_dhcpv4_dev_init(const struct device *dev)
269 {
270 	ARG_UNUSED(dev);
271 
272 	return 0;
273 }
274 
net_dhcpv4_get_mac(const struct device * dev)275 static uint8_t *net_dhcpv4_get_mac(const struct device *dev)
276 {
277 	struct net_dhcpv4_context *context = dev->data;
278 
279 	if (context->mac_addr[2] == 0x00) {
280 		/* 00-00-5E-00-53-xx Documentation RFC 7042 */
281 		context->mac_addr[0] = 0x00;
282 		context->mac_addr[1] = 0x00;
283 		context->mac_addr[2] = 0x5E;
284 		context->mac_addr[3] = 0x00;
285 		context->mac_addr[4] = 0x53;
286 		context->mac_addr[5] = 0x01;
287 	}
288 
289 	return context->mac_addr;
290 }
291 
net_dhcpv4_iface_init(struct net_if * iface)292 static void net_dhcpv4_iface_init(struct net_if *iface)
293 {
294 	uint8_t *mac = net_dhcpv4_get_mac(net_if_get_device(iface));
295 
296 	net_if_set_link_addr(iface, mac, 6, NET_LINK_ETHERNET);
297 }
298 
prepare_dhcp_offer(struct net_if * iface,uint32_t xid)299 struct net_pkt *prepare_dhcp_offer(struct net_if *iface, uint32_t xid)
300 {
301 	struct net_pkt *pkt;
302 
303 	pkt = net_pkt_alloc_with_buffer(iface, sizeof(offer), AF_INET,
304 					IPPROTO_UDP, K_FOREVER);
305 	if (!pkt) {
306 		return NULL;
307 	}
308 
309 	net_pkt_set_ipv4_ttl(pkt, 0xFF);
310 
311 	if (net_ipv4_create(pkt, &server_addr, &client_addr) ||
312 	    net_udp_create(pkt, htons(SERVER_PORT), htons(CLIENT_PORT))) {
313 		goto fail;
314 	}
315 
316 	if (net_pkt_write(pkt, offer, 4)) {
317 		goto fail;
318 	}
319 
320 	/* Update xid from the client request */
321 	if (net_pkt_write_be32(pkt, xid)) {
322 		goto fail;
323 	}
324 
325 	if (net_pkt_write(pkt, offer + 8, sizeof(offer) - 8)) {
326 		goto fail;
327 	}
328 
329 	net_pkt_cursor_init(pkt);
330 
331 	net_ipv4_finalize(pkt, IPPROTO_UDP);
332 
333 	offer_xid = xid;
334 
335 	return pkt;
336 
337 fail:
338 	net_pkt_unref(pkt);
339 	return NULL;
340 }
341 
prepare_dhcp_ack(struct net_if * iface,uint32_t xid)342 struct net_pkt *prepare_dhcp_ack(struct net_if *iface, uint32_t xid)
343 {
344 	struct net_pkt *pkt;
345 
346 	pkt = net_pkt_alloc_with_buffer(iface, sizeof(offer), AF_INET,
347 					IPPROTO_UDP, K_FOREVER);
348 	if (!pkt) {
349 		return NULL;
350 	}
351 
352 	net_pkt_set_ipv4_ttl(pkt, 0xFF);
353 
354 	if (net_ipv4_create(pkt, &server_addr, &client_addr) ||
355 	    net_udp_create(pkt, htons(SERVER_PORT), htons(CLIENT_PORT))) {
356 		goto fail;
357 	}
358 
359 	if (net_pkt_write(pkt, ack, 4)) {
360 		goto fail;
361 	}
362 
363 	/* Update xid from the client request */
364 	if (net_pkt_write_be32(pkt, xid)) {
365 		goto fail;
366 	}
367 
368 	if (net_pkt_write(pkt, ack + 8, sizeof(ack) - 8)) {
369 		goto fail;
370 	}
371 
372 	net_pkt_cursor_init(pkt);
373 
374 	net_ipv4_finalize(pkt, IPPROTO_UDP);
375 
376 	return pkt;
377 
378 fail:
379 	net_pkt_unref(pkt);
380 	return NULL;
381 }
382 
parse_dhcp_message(struct net_pkt * pkt,struct dhcp_msg * msg)383 static int parse_dhcp_message(struct net_pkt *pkt, struct dhcp_msg *msg)
384 {
385 	/* Skip IPv4 and UDP headers */
386 	if (net_pkt_skip(pkt, NET_IPV4UDPH_LEN)) {
387 		return 0;
388 	}
389 
390 	/* Skip DHCPv4 headers (size of op, htype, hlen, hops) */
391 	if (net_pkt_skip(pkt, 4)) {
392 		return 0;
393 	}
394 
395 	if (net_pkt_read_be32(pkt, &msg->xid)) {
396 		return 0;
397 	}
398 
399 	/* Skip DHCPv4 Options (size of op, htype, ... cookie) */
400 	if (net_pkt_skip(pkt, 36 + 64 + 128 + 4)) {
401 		return 0;
402 	}
403 
404 	while (1) {
405 		uint8_t length = 0U;
406 		uint8_t type;
407 
408 		if (net_pkt_read_u8(pkt, &type)) {
409 			return 0;
410 		}
411 
412 		if (type == MSG_TYPE) {
413 			if (net_pkt_skip(pkt, 1)) {
414 				return 0;
415 			}
416 
417 			if (net_pkt_read_u8(pkt, &msg->type)) {
418 				return 0;
419 			}
420 
421 			if (msg->type == NET_DHCPV4_MSG_TYPE_REQUEST) {
422 				request_xid = msg->xid;
423 			}
424 
425 			return 1;
426 		}
427 
428 		if (net_pkt_read_u8(pkt, &length)) {
429 			return 0;
430 		}
431 
432 		if (length && net_pkt_skip(pkt, length)) {
433 			return 0;
434 		}
435 	}
436 
437 	return 0;
438 }
439 
tester_send(const struct device * dev,struct net_pkt * pkt)440 static int tester_send(const struct device *dev, struct net_pkt *pkt)
441 {
442 	struct net_pkt *rpkt;
443 	struct dhcp_msg msg;
444 
445 	(void)memset(&msg, 0, sizeof(msg));
446 
447 	if (!pkt->frags) {
448 		TC_PRINT("No data to send!\n");
449 
450 		return -ENODATA;
451 	}
452 
453 	parse_dhcp_message(pkt, &msg);
454 
455 	if (msg.type == DISCOVER) {
456 		/* Reply with DHCPv4 offer message */
457 		rpkt = prepare_dhcp_offer(net_pkt_iface(pkt), msg.xid);
458 		if (!rpkt) {
459 			return -EINVAL;
460 		}
461 		k_event_post(&events, EVT_DHCP_OFFER);
462 	} else if (msg.type == REQUEST) {
463 		/* Reply with DHCPv4 ACK message */
464 		rpkt = prepare_dhcp_ack(net_pkt_iface(pkt), msg.xid);
465 		if (!rpkt) {
466 			return -EINVAL;
467 		}
468 		k_event_post(&events, EVT_DHCP_ACK);
469 	} else {
470 		/* Invalid message type received */
471 		return -EINVAL;
472 	}
473 
474 	if (net_recv_data(net_pkt_iface(rpkt), rpkt)) {
475 		net_pkt_unref(rpkt);
476 
477 		return -EINVAL;
478 	}
479 
480 	return 0;
481 }
482 
483 struct net_dhcpv4_context net_dhcpv4_context_data;
484 
485 static struct dummy_api net_dhcpv4_if_api = {
486 	.iface_api.init = net_dhcpv4_iface_init,
487 	.send = tester_send,
488 };
489 
490 NET_DEVICE_INIT(net_dhcpv4_test, "net_dhcpv4_test",
491 		net_dhcpv4_dev_init, NULL,
492 		&net_dhcpv4_context_data, NULL,
493 		CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
494 		&net_dhcpv4_if_api, DUMMY_L2,
495 		NET_L2_GET_CTX_TYPE(DUMMY_L2), 127);
496 
497 #ifdef CONFIG_NET_DHCPV4_OPTION_CALLBACKS
498 static struct net_dhcpv4_option_callback opt_domain_cb;
499 static struct net_dhcpv4_option_callback opt_pop3_cb;
500 static struct net_dhcpv4_option_callback opt_invalid_cb;
501 static uint8_t buffer[15];
502 #endif
503 #ifdef CONFIG_NET_DHCPV4_OPTION_CALLBACKS_VENDOR_SPECIFIC
504 static struct net_dhcpv4_option_callback opt_vs_string_cb;
505 static struct net_dhcpv4_option_callback opt_vs_byte_cb;
506 static struct net_dhcpv4_option_callback opt_vs_empty_cb;
507 static struct net_dhcpv4_option_callback opt_vs_invalid_cb;
508 #endif
509 
receiver_cb(uint64_t nm_event,struct net_if * iface,void * info,size_t info_length,void * user_data)510 static void receiver_cb(uint64_t nm_event, struct net_if *iface, void *info, size_t info_length,
511 			void *user_data)
512 {
513 	const struct in_addr ip_addr = { { { 10, 237, 72, 158 } } };
514 	const struct in_addr dns_addrs[3] = {
515 		{ { { 10, 248, 2, 1 } } },
516 		{ { { 163, 33, 253, 68 } } },
517 		{ { { 10, 184, 9, 1 } } },
518 	};
519 
520 	ARG_UNUSED(iface);
521 	ARG_UNUSED(user_data);
522 
523 	switch (nm_event) {
524 	case NET_EVENT_IPV4_ADDR_ADD:
525 		zassert_equal(info_length, sizeof(struct in_addr));
526 		zassert_mem_equal(info, &ip_addr, sizeof(struct in_addr));
527 		k_event_post(&events, EVT_ADDR_ADD);
528 		break;
529 	case NET_EVENT_IPV4_ADDR_DEL:
530 		k_event_post(&events, EVT_ADDR_DEL);
531 		break;
532 	case NET_EVENT_DNS_SERVER_ADD:
533 		zassert_equal(info_length, sizeof(struct sockaddr));
534 		if (net_sin(info)->sin_addr.s_addr == dns_addrs[0].s_addr) {
535 			k_event_post(&events, EVT_DNS_SERVER1_ADD);
536 		} else if (net_sin(info)->sin_addr.s_addr == dns_addrs[1].s_addr) {
537 			k_event_post(&events, EVT_DNS_SERVER2_ADD);
538 		} else if (net_sin(info)->sin_addr.s_addr == dns_addrs[2].s_addr) {
539 			k_event_post(&events, EVT_DNS_SERVER3_ADD);
540 		} else {
541 			zassert_unreachable("Unknown DNS server");
542 		}
543 		break;
544 	case NET_EVENT_DNS_SERVER_DEL:
545 		zassert_equal(info_length, sizeof(struct sockaddr));
546 		if (net_sin(info)->sin_addr.s_addr == dns_addrs[0].s_addr) {
547 			k_event_post(&events, EVT_DNS_SERVER1_DEL);
548 		} else if (net_sin(info)->sin_addr.s_addr == dns_addrs[1].s_addr) {
549 			k_event_post(&events, EVT_DNS_SERVER2_DEL);
550 		} else if (net_sin(info)->sin_addr.s_addr == dns_addrs[2].s_addr) {
551 			k_event_post(&events, EVT_DNS_SERVER3_DEL);
552 		} else {
553 			zassert_unreachable("Unknown DNS server");
554 		}
555 		break;
556 	case NET_EVENT_IPV4_DHCP_START:
557 		k_event_post(&events, EVT_DHCP_START);
558 		break;
559 	case NET_EVENT_IPV4_DHCP_BOUND:
560 		k_event_post(&events, EVT_DHCP_BOUND);
561 		break;
562 	case NET_EVENT_IPV4_DHCP_STOP:
563 		k_event_post(&events, EVT_DHCP_STOP);
564 		break;
565 	}
566 }
567 
568 NET_MGMT_REGISTER_EVENT_HANDLER(rx_cb, NET_EVENT_IPV4_ADDR_ADD | NET_EVENT_IPV4_ADDR_DEL,
569 				receiver_cb, NULL);
570 NET_MGMT_REGISTER_EVENT_HANDLER(dns_cb, NET_EVENT_DNS_SERVER_ADD | NET_EVENT_DNS_SERVER_DEL,
571 				receiver_cb, NULL);
572 NET_MGMT_REGISTER_EVENT_HANDLER(dhcp_cb,
573 				NET_EVENT_IPV4_DHCP_START | NET_EVENT_IPV4_DHCP_BOUND |
574 					NET_EVENT_IPV4_DHCP_STOP,
575 				receiver_cb, NULL);
576 
577 #ifdef CONFIG_NET_DHCPV4_OPTION_CALLBACKS
578 
option_domain_cb(struct net_dhcpv4_option_callback * cb,size_t length,enum net_dhcpv4_msg_type msg_type,struct net_if * iface)579 static void option_domain_cb(struct net_dhcpv4_option_callback *cb,
580 			     size_t length,
581 			     enum net_dhcpv4_msg_type msg_type,
582 			     struct net_if *iface)
583 {
584 	static const char expectation[] = "fi.intel.com";
585 
586 	ARG_UNUSED(msg_type);
587 	ARG_UNUSED(iface);
588 
589 	zassert_equal(cb->option, OPTION_DOMAIN, "Unexpected option value");
590 	zassert_equal(length, sizeof(expectation), "Incorrect data length");
591 	zassert_mem_equal(buffer, expectation, sizeof(expectation),
592 			  "Incorrect buffer contents");
593 
594 	k_event_post(&events, EVT_OPTION_DOMAIN);
595 }
596 
option_pop3_cb(struct net_dhcpv4_option_callback * cb,size_t length,enum net_dhcpv4_msg_type msg_type,struct net_if * iface)597 static void option_pop3_cb(struct net_dhcpv4_option_callback *cb,
598 			   size_t length,
599 			   enum net_dhcpv4_msg_type msg_type,
600 			   struct net_if *iface)
601 {
602 	static const uint8_t expectation[4] = { 198, 51, 100, 16 };
603 
604 	ARG_UNUSED(msg_type);
605 	ARG_UNUSED(iface);
606 
607 	zassert_equal(cb->option, OPTION_POP3, "Unexpected option value");
608 	zassert_equal(length, sizeof(expectation), "Incorrect data length");
609 	zassert_mem_equal(buffer, expectation, sizeof(expectation),
610 			  "Incorrect buffer contents");
611 
612 	k_event_post(&events, EVT_OPTION_POP3);
613 }
614 
option_invalid_cb(struct net_dhcpv4_option_callback * cb,size_t length,enum net_dhcpv4_msg_type msg_type,struct net_if * iface)615 static void option_invalid_cb(struct net_dhcpv4_option_callback *cb,
616 			      size_t length,
617 			      enum net_dhcpv4_msg_type msg_type,
618 			      struct net_if *iface)
619 {
620 	ARG_UNUSED(cb);
621 	ARG_UNUSED(length);
622 	ARG_UNUSED(msg_type);
623 	ARG_UNUSED(iface);
624 
625 	/* This function should never be called. If it is, the parser took a wrong turn. */
626 	zassert_unreachable("Unexpected callback - incorrect parsing of vendor sepcific options");
627 }
628 
629 #ifdef CONFIG_NET_DHCPV4_OPTION_CALLBACKS_VENDOR_SPECIFIC
630 
vendor_specific_string_cb(struct net_dhcpv4_option_callback * cb,size_t length,enum net_dhcpv4_msg_type msg_type,struct net_if * iface)631 static void vendor_specific_string_cb(struct net_dhcpv4_option_callback *cb,
632 				      size_t length,
633 				      enum net_dhcpv4_msg_type msg_type,
634 				      struct net_if *iface)
635 {
636 	static const char expectation[] = "string";
637 
638 	ARG_UNUSED(msg_type);
639 	ARG_UNUSED(iface);
640 
641 	zassert_equal(cb->option, OPTION_VENDOR_STRING,
642 		      "Unexpected vendor specific option value");
643 	zassert_equal(length, sizeof(expectation), "Incorrect data length");
644 	zassert_mem_equal(buffer, expectation, sizeof(expectation), "Incorrect buffer contents");
645 
646 	k_event_post(&events, EVT_VENDOR_STRING);
647 }
648 
vendor_specific_byte_cb(struct net_dhcpv4_option_callback * cb,size_t length,enum net_dhcpv4_msg_type msg_type,struct net_if * iface)649 static void vendor_specific_byte_cb(struct net_dhcpv4_option_callback *cb,
650 				    size_t length,
651 				    enum net_dhcpv4_msg_type msg_type,
652 				    struct net_if *iface)
653 {
654 	ARG_UNUSED(msg_type);
655 	ARG_UNUSED(iface);
656 
657 	zassert_equal(cb->option, OPTION_VENDOR_BYTE,
658 		      "Unexpected vendor specific option value");
659 	zassert_equal(length, 1, "Incorrect data length");
660 	zassert_equal(buffer[0], 1, "Incorrect buffer contents");
661 
662 	k_event_post(&events, EVT_VENDOR_BYTE);
663 }
664 
vendor_specific_empty_cb(struct net_dhcpv4_option_callback * cb,size_t length,enum net_dhcpv4_msg_type msg_type,struct net_if * iface)665 static void vendor_specific_empty_cb(struct net_dhcpv4_option_callback *cb,
666 				     size_t length,
667 				     enum net_dhcpv4_msg_type msg_type,
668 				     struct net_if *iface)
669 {
670 	ARG_UNUSED(msg_type);
671 	ARG_UNUSED(iface);
672 
673 	zassert_equal(cb->option, OPTION_VENDOR_EMPTY,
674 		      "Unexpected vendor specific option value");
675 	zassert_equal(length, 0, "Incorrect data length");
676 
677 	k_event_post(&events, EVT_VENDOR_EMPTY);
678 }
679 
680 #endif /* CONFIG_NET_DHCPV4_OPTION_CALLBACKS_VENDOR_SPECIFIC */
681 
682 #endif /* CONFIG_NET_DHCPV4_OPTION_CALLBACKS */
683 
ZTEST(dhcpv4_tests,test_dhcp)684 ZTEST(dhcpv4_tests, test_dhcp)
685 {
686 	struct net_if *iface;
687 	uint32_t evt;
688 
689 #ifdef CONFIG_NET_DHCPV4_OPTION_CALLBACKS
690 	net_dhcpv4_init_option_callback(&opt_domain_cb, option_domain_cb,
691 					OPTION_DOMAIN, buffer,
692 					sizeof(buffer));
693 
694 	net_dhcpv4_add_option_callback(&opt_domain_cb);
695 
696 	net_dhcpv4_init_option_callback(&opt_pop3_cb, option_pop3_cb,
697 					OPTION_POP3, buffer,
698 					sizeof(buffer));
699 
700 	net_dhcpv4_add_option_callback(&opt_pop3_cb);
701 
702 	net_dhcpv4_init_option_callback(&opt_invalid_cb, option_invalid_cb,
703 					OPTION_INVALID, buffer,
704 					sizeof(buffer));
705 
706 	net_dhcpv4_add_option_callback(&opt_invalid_cb);
707 #endif /* CONFIG_NET_DHCPV4_OPTION_CALLBACKS */
708 
709 #ifdef CONFIG_NET_DHCPV4_OPTION_CALLBACKS_VENDOR_SPECIFIC
710 	net_dhcpv4_init_option_vendor_callback(&opt_vs_string_cb, vendor_specific_string_cb,
711 					       OPTION_VENDOR_STRING, buffer,
712 					       sizeof(buffer));
713 
714 	net_dhcpv4_add_option_vendor_callback(&opt_vs_string_cb);
715 
716 	net_dhcpv4_init_option_vendor_callback(&opt_vs_byte_cb, vendor_specific_byte_cb,
717 					       OPTION_VENDOR_BYTE, buffer,
718 					       sizeof(buffer));
719 
720 	net_dhcpv4_add_option_vendor_callback(&opt_vs_byte_cb);
721 
722 	net_dhcpv4_init_option_vendor_callback(&opt_vs_empty_cb, vendor_specific_empty_cb,
723 					       OPTION_VENDOR_EMPTY, buffer,
724 					       sizeof(buffer));
725 
726 	net_dhcpv4_add_option_vendor_callback(&opt_vs_empty_cb);
727 
728 	net_dhcpv4_init_option_vendor_callback(&opt_vs_invalid_cb, option_invalid_cb,
729 					       OPTION_INVALID, buffer,
730 					       sizeof(buffer));
731 
732 	net_dhcpv4_add_option_vendor_callback(&opt_vs_invalid_cb);
733 
734 
735 #endif /* CONFIG_NET_DHCPV4_OPTION_CALLBACKS_VENDOR_SPECIFIC */
736 
737 	iface = net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY));
738 	if (!iface) {
739 		zassert_true(false, "Interface not available");
740 	}
741 
742 	for (int loop = 0; loop < 2; ++loop) {
743 		LOG_DBG("Running DHCPv4 loop %d", loop);
744 		net_dhcpv4_start(iface);
745 
746 		evt = k_event_wait(&events, EVT_DHCP_START, false, WAIT_TIME);
747 		zassert_equal(evt, EVT_DHCP_START, "Missing DHCP start");
748 
749 #ifdef CONFIG_NET_DHCPV4_OPTION_CALLBACKS
750 		evt = k_event_wait_all(&events, EVT_OPTION_DOMAIN | EVT_OPTION_POP3, false,
751 				       WAIT_TIME);
752 		zassert_equal(evt, EVT_OPTION_DOMAIN | EVT_OPTION_POP3,
753 			      "Missing DHCP option(s) %08x", evt);
754 #endif
755 
756 #ifdef CONFIG_NET_DHCPV4_OPTION_CALLBACKS_VENDOR_SPECIFIC
757 		evt = k_event_wait_all(&events,
758 				       EVT_VENDOR_STRING | EVT_VENDOR_BYTE | EVT_VENDOR_EMPTY,
759 				       false, WAIT_TIME);
760 		zassert_equal(evt, EVT_VENDOR_STRING | EVT_VENDOR_BYTE | EVT_VENDOR_EMPTY,
761 			      "Missing DHCP vendor option(s) %08x", evt);
762 #endif
763 
764 		evt = k_event_wait_all(&events,
765 				       EVT_DNS_SERVER1_ADD | EVT_DNS_SERVER2_ADD |
766 				       EVT_DNS_SERVER3_ADD,
767 				       false, WAIT_TIME);
768 		zassert_equal(evt,
769 			      EVT_DNS_SERVER1_ADD | EVT_DNS_SERVER2_ADD |
770 			      EVT_DNS_SERVER3_ADD,
771 			      "Missing DNS server(s) %08x", evt);
772 
773 		evt = k_event_wait(&events, EVT_DHCP_BOUND, false, WAIT_TIME);
774 		zassert_equal(evt, EVT_DHCP_BOUND, "Missing DHCP bound");
775 
776 		if (loop == 0 || !IS_ENABLED(CONFIG_NET_DHCPV4_INIT_REBOOT)) {
777 			evt = k_event_wait_all(&events, EVT_DHCP_OFFER | EVT_DHCP_ACK, false,
778 					       WAIT_TIME);
779 			zassert_equal(evt, EVT_DHCP_OFFER | EVT_DHCP_ACK,
780 				      "Missing offer or ack %08x", evt);
781 
782 			/* Verify that Request xid matched Offer xid. */
783 			zassert_equal(offer_xid, request_xid,
784 				      "Offer/Request xid mismatch, "
785 				      "Offer 0x%08x, Request 0x%08x",
786 				      offer_xid, request_xid);
787 		} else {
788 			/* An init-reboot was done */
789 			evt = k_event_wait(&events, EVT_DHCP_OFFER | EVT_DHCP_ACK, false,
790 					   WAIT_TIME);
791 			zassert_equal(evt, EVT_DHCP_ACK, "Ack only expected %08x", evt);
792 		}
793 
794 		/* Clear all events */
795 		k_event_set(&events, 0U);
796 
797 		net_dhcpv4_stop(iface);
798 
799 		evt = k_event_wait_all(&events,
800 				       EVT_DHCP_STOP | EVT_ADDR_DEL |
801 				       EVT_DNS_SERVER1_DEL | EVT_DNS_SERVER2_DEL |
802 				       EVT_DNS_SERVER3_DEL,
803 				       false, WAIT_TIME);
804 		zassert_equal(evt,
805 			      EVT_DHCP_STOP | EVT_ADDR_DEL |
806 			      EVT_DNS_SERVER1_DEL | EVT_DNS_SERVER2_DEL |
807 			      EVT_DNS_SERVER3_DEL,
808 			      "Missing DHCP stop or deleted address");
809 	}
810 }
811 
812 /**test case main entry */
813 ZTEST_SUITE(dhcpv4_tests, NULL, NULL, NULL, NULL, NULL);
814