1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * efi_selftest_ipconfig
4  *
5  * This unit test covers the IPv4 Config2 Protocol.
6  *
7  */
8 
9 #include <efi_selftest.h>
10 #include <charset.h>
11 #include <net.h>
12 
13 static struct efi_boot_services *boottime;
14 
15 static struct efi_ip4_config2_protocol *ip4_config2;
16 static const efi_guid_t efi_ip4_config2_guid = EFI_IP4_CONFIG2_PROTOCOL_GUID;
17 
18 /*
19  * Setup unit test.
20  *
21  * Open IPv4 Config2 protocol
22  *
23  * @handle:	handle of the loaded image
24  * @systable:	system table
25  * Return:	EFI_ST_SUCCESS for success
26  */
setup(const efi_handle_t handle,const struct efi_system_table * systable)27 static int setup(const efi_handle_t handle,
28 		 const struct efi_system_table *systable)
29 {
30 	efi_status_t ret;
31 	efi_handle_t *net_handle;
32 	efi_uintn_t num_handles;
33 	efi_handle_t *handles;
34 
35 	boottime = systable->boottime;
36 
37 	num_handles = 0;
38 	boottime->locate_handle_buffer(BY_PROTOCOL, &efi_ip4_config2_guid,
39 				       NULL, &num_handles, &handles);
40 
41 	if (!num_handles) {
42 		efi_st_error("Failed to locate ipv4 config2 protocol\n");
43 		return EFI_ST_FAILURE;
44 	}
45 
46 	for (net_handle = handles; num_handles--; net_handle++) {
47 		ret = boottime->open_protocol(*net_handle, &efi_ip4_config2_guid,
48 					      (void **)&ip4_config2, 0, 0,
49 					      EFI_OPEN_PROTOCOL_GET_PROTOCOL);
50 		if (ret != EFI_SUCCESS || !ip4_config2)
51 			continue;
52 		break; // Get first handle that supports ipv4
53 	}
54 
55 	if (!ip4_config2) {
56 		efi_st_error("Failed to open ipv4 config2 protocol\n");
57 		return EFI_ST_FAILURE;
58 	}
59 
60 	return EFI_ST_SUCCESS;
61 }
62 
63 /*
64  * Execute unit test.
65  *
66  *
67  * Return:	EFI_ST_SUCCESS for success
68  */
execute(void)69 static int execute(void)
70 {
71 	efi_status_t ret;
72 	enum efi_ip4_config2_policy policy;
73 	efi_uintn_t data_size;
74 	struct efi_ip4_config2_manual_address manual_address;
75 	struct efi_ip4_config2_manual_address orig_address;
76 	u8 netmask[] = {255, 255, 255, 0};
77 	u8 ip[] = {10, 0, 0, 1};
78 
79 	/* Setup may have failed */
80 	if (!ip4_config2) {
81 		efi_st_error("Setup failure, cannot proceed with test\n");
82 		return EFI_ST_FAILURE;
83 	}
84 
85 	/* Set policy to static */
86 	policy = EFI_IP4_CONFIG2_POLICY_STATIC;
87 	ret = ip4_config2->set_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_POLICY,
88 			      sizeof(policy), (void *)&policy);
89 	if (ret != EFI_SUCCESS) {
90 		efi_st_error("Failed to set policy\n");
91 		return EFI_ST_FAILURE;
92 	}
93 
94 	/* Save original ip address and netmask */
95 	data_size = sizeof(manual_address);
96 	ret = ip4_config2->get_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
97 			      &data_size, &orig_address);
98 	if (ret != EFI_SUCCESS) {
99 		efi_st_error("Failed to save original ip address and netmask\n");
100 		return EFI_ST_FAILURE;
101 	}
102 
103 	/* Set static ip and netmask */
104 	memcpy(&manual_address.address, ip,
105 	       sizeof(struct efi_ipv4_address));
106 	memcpy(&manual_address.subnet_mask, netmask,
107 	       sizeof(struct efi_ipv4_address));
108 	ret = ip4_config2->set_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
109 			      sizeof(manual_address), &manual_address);
110 	if (ret != EFI_SUCCESS) {
111 		efi_st_error("Failed to get ip address and netmask\n");
112 		return EFI_ST_FAILURE;
113 	}
114 
115 	/* Try to set interface info, this should fail */
116 	ret = ip4_config2->set_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, 0, NULL);
117 	if (ret == EFI_SUCCESS) {
118 		efi_st_error("Interface info is read-only\n");
119 		return EFI_ST_FAILURE;
120 	}
121 
122 	/* Get ip address and netmask and check that they match with the previously set ones */
123 	data_size = sizeof(manual_address);
124 	ret = ip4_config2->get_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
125 			      &data_size, &manual_address);
126 	if (ret != EFI_SUCCESS) {
127 		efi_st_error("Failed to get ip address and netmask\n");
128 		return EFI_ST_FAILURE;
129 	}
130 	if (memcmp(ip, &manual_address.address,
131 		   sizeof(struct efi_ipv4_address)) ||
132 	    memcmp(netmask, &manual_address.subnet_mask,
133 		   sizeof(struct efi_ipv4_address))) {
134 		efi_st_error("Ip address mismatch\n");
135 		return EFI_ST_FAILURE;
136 	}
137 
138 	/* Restore original ip address and netmask */
139 	ret = ip4_config2->set_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
140 			      sizeof(orig_address), &orig_address);
141 	if (ret != EFI_SUCCESS) {
142 		efi_st_error("Failed to restore original ip address and netmask\n");
143 		return EFI_ST_FAILURE;
144 	}
145 
146 	efi_st_printf("Efi ipconfig test execute succeeded\n");
147 	return EFI_ST_SUCCESS;
148 }
149 
150 /*
151  * Tear down unit test.
152  *
153  * Return:	EFI_ST_SUCCESS for success
154  */
teardown(void)155 static int teardown(void)
156 {
157 	int exit_status = EFI_ST_SUCCESS;
158 
159 	return exit_status;
160 }
161 
162 EFI_UNIT_TEST(ipconfig) = {
163 	.name = "IPv4 config2 protocol",
164 	.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
165 	.setup = setup,
166 	.execute = execute,
167 	.teardown = teardown,
168 #ifdef CONFIG_SANDBOX
169 	/*
170 	 * Running this test on the sandbox requires setting environment
171 	 * variable ethact to a network interface connected to a DHCP server and
172 	 * ethrotate to 'no'.
173 	 */
174 	.on_request = true,
175 #endif
176 };
177