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[420] = {
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 /* [53] DHCP Message Type: OFFER */
74 0x35, 0x01, 0x02,
75 /* [1] Subnet Mask: 255.255.255.0 */
76 0x01, 0x04, 0xff, 0xff, 0xff, 0x00,
77 /* [58] Renewal Time Value: (21600s) 6 hours */
78 0x3a, 0x04, 0x00, 0x00, 0x54, 0x60,
79 /* [59] Rebinding Time Value: (37800s) 1 hour 30 min */
80 0x3b, 0x04, 0x00, 0x00, 0x93, 0xa8,
81 /* [51] IP Address Lease Time: (43200s) 12 hours */
82 0x33, 0x04, 0x00, 0x00, 0xa8, 0xc0,
83 /* [54] DHCP Server Identifier: 10.184.9.1 */
84 0x36, 0x04, 0x0a, 0xb8, 0x09, 0x01,
85 /* [3] Router: 10.237.72.1 */
86 0x03, 0x04, 0x0a, 0xed, 0x48, 0x01,
87 /* [15] Domain Name: fi.intel.com */
88 0x0f, 0x0d, 0x66, 0x69, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x00,
89 /* [6] Domain Name Server: 10.248.2.1 163.33.253.68 10.184.9.1 */
90 0x06, 0x0c, 0x0a, 0xf8, 0x02, 0x01, 0xa3, 0x21, 0xfd, 0x44, 0x0a, 0xb8, 0x09, 0x01,
91 /* [119] Domain Search Option: fi.intel.com ger.corp.intel.com corp.intel.com intel.com */
92 0x77, 0x3d, 0x02, 0x66, 0x69, 0x05, 0x69, 0x6e,
93 0x74, 0x65, 0x6c, 0x03, 0x63, 0x6f, 0x6d, 0x00,
94 0x03, 0x67, 0x65, 0x72, 0x04, 0x63, 0x6f, 0x72,
95 0x70, 0x05, 0x69, 0x6e, 0x74, 0x65, 0x6c, 0x03,
96 0x63, 0x6f, 0x6d, 0x00, 0x04, 0x63, 0x6f, 0x72,
97 0x70, 0x05, 0x69, 0x6e, 0x74, 0x65, 0x6c, 0x03,
98 0x63, 0x6f, 0x6d, 0x00, 0x05, 0x69, 0x6e, 0x74,
99 0x65, 0x6c, 0x03, 0x63, 0x6f, 0x6d, 0x00,
100 /* [44] NetBIOS Name Servers: 163.33.7.86, 143.182.250.105 */
101 0x2c, 0x08, 0xa3, 0x21, 0x07, 0x56, 0x8f, 0xb6, 0xfa, 0x69,
102 /* [43] Encapsulated vendor specific information */
103 0x2b, 0x0a,
104 	    /* [1]: "string" */
105 	    0x01, 0x07, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00,
106 	    /* End marker */
107 	    0xff,
108 /* [43] Encapsulated vendor specific information */
109 0x2b, 0x0f,
110 	    /* [2]: single byte of value 1 */
111 	    0x02, 0x01, 0x01,
112 	    /* [3]: zero-length option */
113 	    0x03, 0x00,
114 	    /* [254]: invalid option (size longer than remainder of opt 43 size) */
115 	    0xfe, 0x10, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
116 /* [43] Too short encapsulated vendor option (only single byte) */
117 0x2b, 0x01,
118 	    /* [254]: invalid option (no length in opt 43) */
119 	    0xfe,
120 /* [70] POP3 Server: 198.51.100.16 */
121 0x46, 0x04, 0xc6, 0x33, 0x64, 0x10,
122 /* End marker */
123 0xff
124 };
125 
126 /* Sample DHCPv4 ACK */
127 static const unsigned char ack[420] = {
128 0x02, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130 0x0a, 0xed, 0x48, 0x9e, 0x00, 0x00, 0x00, 0x00,
131 0x0a, 0xed, 0x48, 0x03, 0x00, 0x00, 0x5E, 0x00,
132 0x53, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134 0x00, 0x00, 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,
158 /* Magic cookie: DHCP */
159 0x63, 0x82, 0x53, 0x63,
160 /* [53] DHCP Message Type: ACK */
161 0x35, 0x01, 0x05,
162 /* [58] Renewal Time Value: (21600s) 6 hours */
163 0x3a, 0x04, 0x00, 0x00, 0x54, 0x60,
164 /* [59] Rebinding Time Value: (37800s) 1 hour 30 min */
165 0x3b, 0x04, 0x00, 0x00, 0x93, 0xa8,
166 /* [51] IP Address Lease Time: (43200s) 12 hours */
167 0x33, 0x04, 0x00, 0x00, 0xa8, 0xc0,
168 /* [54] DHCP Server Identifier: 10.184.9.1 */
169 0x36, 0x04, 0x0a, 0xb8, 0x09, 0x01,
170 /* [1] Subnet Mask: 255.255.255.0 */
171 0x01, 0x04, 0xff, 0xff, 0xff, 0x00,
172 /* [3] Router: 10.237.72.1 */
173 0x03, 0x04, 0x0a, 0xed, 0x48, 0x01,
174 /* [15] Domain Name: fi.intel.com */
175 0x0f, 0x0d, 0x66, 0x69, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x00,
176 /* [6] Domain Name Server: 10.248.2.1 163.33.253.68 10.184.9.1 */
177 0x06, 0x0c, 0x0a, 0xf8, 0x02, 0x01, 0xa3, 0x21, 0xfd, 0x44, 0x0a, 0xb8, 0x09, 0x01,
178 /* [119] Domain Search Option: fi.intel.com ger.corp.intel.com corp.intel.com intel.com */
179 0x77, 0x3d, 0x02, 0x66, 0x69, 0x05, 0x69, 0x6e,
180 0x74, 0x65, 0x6c, 0x03, 0x63, 0x6f, 0x6d, 0x00,
181 0x03, 0x67, 0x65, 0x72, 0x04, 0x63, 0x6f, 0x72,
182 0x70, 0x05, 0x69, 0x6e, 0x74, 0x65, 0x6c, 0x03,
183 0x63, 0x6f, 0x6d, 0x00, 0x04, 0x63, 0x6f, 0x72,
184 0x70, 0x05, 0x69, 0x6e, 0x74, 0x65, 0x6c, 0x03,
185 0x63, 0x6f, 0x6d, 0x00, 0x05, 0x69, 0x6e, 0x74,
186 0x65, 0x6c, 0x03, 0x63, 0x6f, 0x6d, 0x00,
187 /* [44] NetBIOS Name Servers: 163.33.7.86, 143.182.250.105 */
188 0x2c, 0x08, 0xa3, 0x21, 0x07, 0x56, 0x8f, 0xb6, 0xfa, 0x69,
189 /* [43] Encapsulated vendor specific information */
190 0x2b, 0x0a,
191 	    /* [1]: "string" */
192 	    0x01, 0x07, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00,
193 	    /* End marker */
194 	    0xff,
195 /* [43] Encapsulated vendor specific information */
196 0x2b, 0x0f,
197 	    /* [2]: single byte of value 1 */
198 	    0x02, 0x01, 0x01,
199 	    /* [3]: zero-length option */
200 	    0x03, 0x00,
201 	    /* [254]: invalid option (size longer than remainder of opt 43 size) */
202 	    0xfe, 0x10, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
203 /* [43] Too short encapsulated vendor option (only single byte) */
204 0x2b, 0x01,
205 	    /* [254]: invalid option (no length in opt 43) */
206 	    0xfe,
207 /* [70] POP3 Server: 198.51.100.16 */
208 0x46, 0x04, 0xc6, 0x33, 0x64, 0x10,
209 /* End marker */
210 0xff
211 };
212 
213 static const struct in_addr server_addr = { { { 192, 0, 2, 1 } } };
214 static const struct in_addr client_addr = { { { 255, 255, 255, 255 } } };
215 
216 #define SERVER_PORT		67
217 #define CLIENT_PORT		68
218 #define MSG_TYPE		53
219 #define DISCOVER		1
220 #define REQUEST			3
221 #define OPTION_DOMAIN		15
222 #define OPTION_POP3		70
223 #define OPTION_VENDOR_STRING	1
224 #define OPTION_VENDOR_BYTE	2
225 #define OPTION_VENDOR_EMPTY	3
226 #define OPTION_INVALID		254
227 
228 struct dhcp_msg {
229 	uint32_t xid;
230 	uint8_t type;
231 };
232 
233 static struct k_sem test_lock;
234 
235 #define WAIT_TIME K_SECONDS(CONFIG_NET_DHCPV4_INITIAL_DELAY_MAX + 1)
236 
237 struct net_dhcpv4_context {
238 	uint8_t mac_addr[sizeof(struct net_eth_addr)];
239 	struct net_linkaddr ll_addr;
240 };
241 
net_dhcpv4_dev_init(const struct device * dev)242 static int net_dhcpv4_dev_init(const struct device *dev)
243 {
244 	struct net_dhcpv4_context *net_dhcpv4_context = dev->data;
245 
246 	net_dhcpv4_context = net_dhcpv4_context;
247 
248 	return 0;
249 }
250 
net_dhcpv4_get_mac(const struct device * dev)251 static uint8_t *net_dhcpv4_get_mac(const struct device *dev)
252 {
253 	struct net_dhcpv4_context *context = dev->data;
254 
255 	if (context->mac_addr[2] == 0x00) {
256 		/* 00-00-5E-00-53-xx Documentation RFC 7042 */
257 		context->mac_addr[0] = 0x00;
258 		context->mac_addr[1] = 0x00;
259 		context->mac_addr[2] = 0x5E;
260 		context->mac_addr[3] = 0x00;
261 		context->mac_addr[4] = 0x53;
262 		context->mac_addr[5] = 0x01;
263 	}
264 
265 	return context->mac_addr;
266 }
267 
net_dhcpv4_iface_init(struct net_if * iface)268 static void net_dhcpv4_iface_init(struct net_if *iface)
269 {
270 	uint8_t *mac = net_dhcpv4_get_mac(net_if_get_device(iface));
271 
272 	net_if_set_link_addr(iface, mac, 6, NET_LINK_ETHERNET);
273 }
274 
prepare_dhcp_offer(struct net_if * iface,uint32_t xid)275 struct net_pkt *prepare_dhcp_offer(struct net_if *iface, uint32_t xid)
276 {
277 	struct net_pkt *pkt;
278 
279 	pkt = net_pkt_alloc_with_buffer(iface, sizeof(offer), AF_INET,
280 					IPPROTO_UDP, K_FOREVER);
281 	if (!pkt) {
282 		return NULL;
283 	}
284 
285 	net_pkt_set_ipv4_ttl(pkt, 0xFF);
286 
287 	if (net_ipv4_create(pkt, &server_addr, &client_addr) ||
288 	    net_udp_create(pkt, htons(SERVER_PORT), htons(CLIENT_PORT))) {
289 		goto fail;
290 	}
291 
292 	if (net_pkt_write(pkt, offer, 4)) {
293 		goto fail;
294 	}
295 
296 	/* Update xid from the client request */
297 	if (net_pkt_write_be32(pkt, xid)) {
298 		goto fail;
299 	}
300 
301 	if (net_pkt_write(pkt, offer + 8, sizeof(offer) - 8)) {
302 		goto fail;
303 	}
304 
305 	net_pkt_cursor_init(pkt);
306 
307 	net_ipv4_finalize(pkt, IPPROTO_UDP);
308 
309 	return pkt;
310 
311 fail:
312 	net_pkt_unref(pkt);
313 	return NULL;
314 }
315 
prepare_dhcp_ack(struct net_if * iface,uint32_t xid)316 struct net_pkt *prepare_dhcp_ack(struct net_if *iface, uint32_t xid)
317 {
318 	struct net_pkt *pkt;
319 
320 	pkt = net_pkt_alloc_with_buffer(iface, sizeof(offer), AF_INET,
321 					IPPROTO_UDP, K_FOREVER);
322 	if (!pkt) {
323 		return NULL;
324 	}
325 
326 	net_pkt_set_ipv4_ttl(pkt, 0xFF);
327 
328 	if (net_ipv4_create(pkt, &server_addr, &client_addr) ||
329 	    net_udp_create(pkt, htons(SERVER_PORT), htons(CLIENT_PORT))) {
330 		goto fail;
331 	}
332 
333 	if (net_pkt_write(pkt, ack, 4)) {
334 		goto fail;
335 	}
336 
337 	/* Update xid from the client request */
338 	if (net_pkt_write_be32(pkt, xid)) {
339 		goto fail;
340 	}
341 
342 	if (net_pkt_write(pkt, ack + 8, sizeof(ack) - 8)) {
343 		goto fail;
344 	}
345 
346 	net_pkt_cursor_init(pkt);
347 
348 	net_ipv4_finalize(pkt, IPPROTO_UDP);
349 
350 	return pkt;
351 
352 fail:
353 	net_pkt_unref(pkt);
354 	return NULL;
355 }
356 
parse_dhcp_message(struct net_pkt * pkt,struct dhcp_msg * msg)357 static int parse_dhcp_message(struct net_pkt *pkt, struct dhcp_msg *msg)
358 {
359 	/* Skip IPv4 and UDP headers */
360 	if (net_pkt_skip(pkt, NET_IPV4UDPH_LEN)) {
361 		return 0;
362 	}
363 
364 	/* Skip DHCPv4 headers (size of op, htype, hlen, hops) */
365 	if (net_pkt_skip(pkt, 4)) {
366 		return 0;
367 	}
368 
369 	if (net_pkt_read_be32(pkt, &msg->xid)) {
370 		return 0;
371 	}
372 
373 	/* Skip DHCPv4 Options (size of op, htype, ... cookie) */
374 	if (net_pkt_skip(pkt, 36 + 64 + 128 + 4)) {
375 		return 0;
376 	}
377 
378 	while (1) {
379 		uint8_t length = 0U;
380 		uint8_t type;
381 
382 		if (net_pkt_read_u8(pkt, &type)) {
383 			return 0;
384 		}
385 
386 		if (type == MSG_TYPE) {
387 			if (net_pkt_skip(pkt, 1)) {
388 				return 0;
389 			}
390 
391 			if (net_pkt_read_u8(pkt, &msg->type)) {
392 				return 0;
393 			}
394 
395 			return 1;
396 		}
397 
398 		if (net_pkt_read_u8(pkt, &length)) {
399 			return 0;
400 		}
401 
402 		if (length && net_pkt_skip(pkt, length)) {
403 			return 0;
404 		}
405 	}
406 
407 	return 0;
408 }
409 
tester_send(const struct device * dev,struct net_pkt * pkt)410 static int tester_send(const struct device *dev, struct net_pkt *pkt)
411 {
412 	struct net_pkt *rpkt;
413 	struct dhcp_msg msg;
414 
415 	(void)memset(&msg, 0, sizeof(msg));
416 
417 	if (!pkt->frags) {
418 		TC_PRINT("No data to send!\n");
419 
420 		return -ENODATA;
421 	}
422 
423 	parse_dhcp_message(pkt, &msg);
424 
425 	if (msg.type == DISCOVER) {
426 		/* Reply with DHCPv4 offer message */
427 		rpkt = prepare_dhcp_offer(net_pkt_iface(pkt), msg.xid);
428 		if (!rpkt) {
429 			return -EINVAL;
430 		}
431 	} else if (msg.type == REQUEST) {
432 		/* Reply with DHCPv4 ACK message */
433 		rpkt = prepare_dhcp_ack(net_pkt_iface(pkt), msg.xid);
434 		if (!rpkt) {
435 			return -EINVAL;
436 		}
437 	} else {
438 		/* Invalid message type received */
439 		return -EINVAL;
440 	}
441 
442 	if (net_recv_data(net_pkt_iface(rpkt), rpkt)) {
443 		net_pkt_unref(rpkt);
444 
445 		return -EINVAL;
446 	}
447 
448 	return 0;
449 }
450 
451 struct net_dhcpv4_context net_dhcpv4_context_data;
452 
453 static struct dummy_api net_dhcpv4_if_api = {
454 	.iface_api.init = net_dhcpv4_iface_init,
455 	.send = tester_send,
456 };
457 
458 NET_DEVICE_INIT(net_dhcpv4_test, "net_dhcpv4_test",
459 		net_dhcpv4_dev_init, NULL,
460 		&net_dhcpv4_context_data, NULL,
461 		CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
462 		&net_dhcpv4_if_api, DUMMY_L2,
463 		NET_L2_GET_CTX_TYPE(DUMMY_L2), 127);
464 
465 static struct net_mgmt_event_callback rx_cb;
466 static struct net_mgmt_event_callback dns_cb;
467 static struct net_mgmt_event_callback dhcp_cb;
468 #ifdef CONFIG_NET_DHCPV4_OPTION_CALLBACKS
469 static struct net_dhcpv4_option_callback opt_domain_cb;
470 static struct net_dhcpv4_option_callback opt_pop3_cb;
471 static struct net_dhcpv4_option_callback opt_invalid_cb;
472 static uint8_t buffer[15];
473 #endif
474 #ifdef CONFIG_NET_DHCPV4_OPTION_CALLBACKS_VENDOR_SPECIFIC
475 static struct net_dhcpv4_option_callback opt_vs_string_cb;
476 static struct net_dhcpv4_option_callback opt_vs_byte_cb;
477 static struct net_dhcpv4_option_callback opt_vs_empty_cb;
478 static struct net_dhcpv4_option_callback opt_vs_invalid_cb;
479 #endif
480 static int event_count;
481 
receiver_cb(struct net_mgmt_event_callback * cb,uint32_t nm_event,struct net_if * iface)482 static void receiver_cb(struct net_mgmt_event_callback *cb,
483 			uint32_t nm_event, struct net_if *iface)
484 {
485 	if (nm_event != NET_EVENT_IPV4_ADDR_ADD &&
486 	    nm_event != NET_EVENT_DNS_SERVER_ADD &&
487 	    nm_event != NET_EVENT_DNS_SERVER_DEL &&
488 	    nm_event != NET_EVENT_IPV4_DHCP_START &&
489 	    nm_event != NET_EVENT_IPV4_DHCP_BOUND) {
490 		/* Spurious callback. */
491 		return;
492 	}
493 
494 	event_count++;
495 
496 	k_sem_give(&test_lock);
497 }
498 
499 #ifdef CONFIG_NET_DHCPV4_OPTION_CALLBACKS
500 
option_domain_cb(struct net_dhcpv4_option_callback * cb,size_t length,enum net_dhcpv4_msg_type msg_type,struct net_if * iface)501 static void option_domain_cb(struct net_dhcpv4_option_callback *cb,
502 			     size_t length,
503 			     enum net_dhcpv4_msg_type msg_type,
504 			     struct net_if *iface)
505 {
506 	char expectation[] = "fi.intel.com";
507 
508 	zassert_equal(cb->option, OPTION_DOMAIN, "Unexpected option value");
509 	zassert_equal(length, sizeof(expectation), "Incorrect data length");
510 	zassert_mem_equal(buffer, expectation, sizeof(expectation),
511 			  "Incorrect buffer contents");
512 
513 	event_count++;
514 
515 	k_sem_give(&test_lock);
516 }
517 
option_pop3_cb(struct net_dhcpv4_option_callback * cb,size_t length,enum net_dhcpv4_msg_type msg_type,struct net_if * iface)518 static void option_pop3_cb(struct net_dhcpv4_option_callback *cb,
519 			   size_t length,
520 			   enum net_dhcpv4_msg_type msg_type,
521 			   struct net_if *iface)
522 {
523 	uint8_t expectation[4];
524 
525 	expectation[0] = 198;
526 	expectation[1] = 51;
527 	expectation[2] = 100;
528 	expectation[3] = 16;
529 
530 	zassert_equal(cb->option, OPTION_POP3, "Unexpected option value");
531 	zassert_equal(length, sizeof(expectation), "Incorrect data length");
532 	zassert_mem_equal(buffer, expectation, sizeof(expectation),
533 			  "Incorrect buffer contents");
534 
535 	event_count++;
536 
537 	k_sem_give(&test_lock);
538 }
539 
option_invalid_cb(struct net_dhcpv4_option_callback * cb,size_t length,enum net_dhcpv4_msg_type msg_type,struct net_if * iface)540 static void option_invalid_cb(struct net_dhcpv4_option_callback *cb,
541 			      size_t length,
542 			      enum net_dhcpv4_msg_type msg_type,
543 			      struct net_if *iface)
544 {
545 	/* This function should never be called. If it is, the parser took a wrong turn. */
546 	zassert_true(false, "Unexpected callback - incorrect parsing of vendor sepcific options");
547 }
548 
549 #ifdef CONFIG_NET_DHCPV4_OPTION_CALLBACKS_VENDOR_SPECIFIC
550 
vendor_specific_string_cb(struct net_dhcpv4_option_callback * cb,size_t length,enum net_dhcpv4_msg_type msg_type,struct net_if * iface)551 static void vendor_specific_string_cb(struct net_dhcpv4_option_callback *cb,
552 				      size_t length,
553 				      enum net_dhcpv4_msg_type msg_type,
554 				      struct net_if *iface)
555 {
556 	char expectation[] = "string";
557 
558 	zassert_equal(cb->option, OPTION_VENDOR_STRING,
559 		      "Unexpected vendor specific option value");
560 	zassert_equal(length, sizeof(expectation), "Incorrect data length");
561 	zassert_mem_equal(buffer, expectation, sizeof(expectation), "Incorrect buffer contents");
562 
563 	event_count++;
564 
565 	k_sem_give(&test_lock);
566 }
567 
vendor_specific_byte_cb(struct net_dhcpv4_option_callback * cb,size_t length,enum net_dhcpv4_msg_type msg_type,struct net_if * iface)568 static void vendor_specific_byte_cb(struct net_dhcpv4_option_callback *cb,
569 				    size_t length,
570 				    enum net_dhcpv4_msg_type msg_type,
571 				    struct net_if *iface)
572 {
573 	zassert_equal(cb->option, OPTION_VENDOR_BYTE,
574 		      "Unexpected vendor specific option value");
575 	zassert_equal(length, 1, "Incorrect data length");
576 	zassert_equal(buffer[0], 1, "Incorrect buffer contents");
577 
578 	event_count++;
579 
580 	k_sem_give(&test_lock);
581 }
582 
vendor_specific_empty_cb(struct net_dhcpv4_option_callback * cb,size_t length,enum net_dhcpv4_msg_type msg_type,struct net_if * iface)583 static void vendor_specific_empty_cb(struct net_dhcpv4_option_callback *cb,
584 				     size_t length,
585 				     enum net_dhcpv4_msg_type msg_type,
586 				     struct net_if *iface)
587 {
588 	zassert_equal(cb->option, OPTION_VENDOR_EMPTY,
589 		      "Unexpected vendor specific option value");
590 	zassert_equal(length, 0, "Incorrect data length");
591 
592 	event_count++;
593 
594 	k_sem_give(&test_lock);
595 }
596 
597 #endif /* CONFIG_NET_DHCPV4_OPTION_CALLBACKS_VENDOR_SPECIFIC */
598 
599 #endif /* CONFIG_NET_DHCPV4_OPTION_CALLBACKS */
600 
ZTEST(dhcpv4_tests,test_dhcp)601 ZTEST(dhcpv4_tests, test_dhcp)
602 {
603 	struct net_if *iface;
604 
605 	k_sem_init(&test_lock, 0, UINT_MAX);
606 
607 	net_mgmt_init_event_callback(&rx_cb, receiver_cb,
608 				     NET_EVENT_IPV4_ADDR_ADD);
609 
610 	net_mgmt_add_event_callback(&rx_cb);
611 
612 	net_mgmt_init_event_callback(&dns_cb, receiver_cb,
613 				     NET_EVENT_DNS_SERVER_ADD |
614 				     NET_EVENT_DNS_SERVER_DEL);
615 
616 	net_mgmt_add_event_callback(&dns_cb);
617 
618 	net_mgmt_init_event_callback(&dhcp_cb, receiver_cb,
619 				     NET_EVENT_IPV4_DHCP_START |
620 				     NET_EVENT_IPV4_DHCP_BOUND);
621 
622 	net_mgmt_add_event_callback(&dhcp_cb);
623 
624 #ifdef CONFIG_NET_DHCPV4_OPTION_CALLBACKS
625 	net_dhcpv4_init_option_callback(&opt_domain_cb, option_domain_cb,
626 					OPTION_DOMAIN, buffer,
627 					sizeof(buffer));
628 
629 	net_dhcpv4_add_option_callback(&opt_domain_cb);
630 
631 	net_dhcpv4_init_option_callback(&opt_pop3_cb, option_pop3_cb,
632 					OPTION_POP3, buffer,
633 					sizeof(buffer));
634 
635 	net_dhcpv4_add_option_callback(&opt_pop3_cb);
636 
637 	net_dhcpv4_init_option_callback(&opt_invalid_cb, option_invalid_cb,
638 					OPTION_INVALID, buffer,
639 					sizeof(buffer));
640 
641 	net_dhcpv4_add_option_callback(&opt_invalid_cb);
642 #endif /* CONFIG_NET_DHCPV4_OPTION_CALLBACKS */
643 
644 #ifdef CONFIG_NET_DHCPV4_OPTION_CALLBACKS_VENDOR_SPECIFIC
645 	net_dhcpv4_init_option_vendor_callback(&opt_vs_string_cb, vendor_specific_string_cb,
646 					       OPTION_VENDOR_STRING, buffer,
647 					       sizeof(buffer));
648 
649 	net_dhcpv4_add_option_vendor_callback(&opt_vs_string_cb);
650 
651 	net_dhcpv4_init_option_vendor_callback(&opt_vs_byte_cb, vendor_specific_byte_cb,
652 					       OPTION_VENDOR_BYTE, buffer,
653 					       sizeof(buffer));
654 
655 	net_dhcpv4_add_option_vendor_callback(&opt_vs_byte_cb);
656 
657 	net_dhcpv4_init_option_vendor_callback(&opt_vs_empty_cb, vendor_specific_empty_cb,
658 					       OPTION_VENDOR_EMPTY, buffer,
659 					       sizeof(buffer));
660 
661 	net_dhcpv4_add_option_vendor_callback(&opt_vs_empty_cb);
662 
663 	net_dhcpv4_init_option_vendor_callback(&opt_vs_invalid_cb, option_invalid_cb,
664 					       OPTION_INVALID, buffer,
665 					       sizeof(buffer));
666 
667 	net_dhcpv4_add_option_vendor_callback(&opt_vs_invalid_cb);
668 
669 
670 #endif /* CONFIG_NET_DHCPV4_OPTION_CALLBACKS_VENDOR_SPECIFIC */
671 
672 	iface = net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY));
673 	if (!iface) {
674 		zassert_true(false, "Interface not available");
675 	}
676 
677 	net_dhcpv4_start(iface);
678 
679 #ifdef CONFIG_NET_DHCPV4_OPTION_CALLBACKS_VENDOR_SPECIFIC
680 	while (event_count < 16) {
681 #elif defined(CONFIG_NET_DHCPV4_OPTION_CALLBACKS)
682 	while (event_count < 10) {
683 #else
684 	while (event_count < 5) {
685 #endif
686 		if (k_sem_take(&test_lock, WAIT_TIME)) {
687 			zassert_true(false, "Timeout while waiting");
688 		}
689 	}
690 }
691 
692 /**test case main entry */
693 ZTEST_SUITE(dhcpv4_tests, NULL, NULL, NULL, NULL, NULL);
694