summaryrefslogtreecommitdiff
path: root/lib/efi_selftest/efi_selftest_ipconfig.c
blob: 8d594f5e193c106d0612773447fe7bcd0934bcf7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * efi_selftest_ipconfig
 *
 * This unit test covers the IPv4 Config2 Protocol.
 *
 */

#include <efi_selftest.h>
#include <charset.h>
#include <net.h>

static struct efi_boot_services *boottime;

static struct efi_ip4_config2_protocol *ip4_config2;
static const efi_guid_t efi_ip4_config2_guid = EFI_IP4_CONFIG2_PROTOCOL_GUID;

/*
 * Setup unit test.
 *
 * Open IPv4 Config2 protocol
 *
 * @handle:	handle of the loaded image
 * @systable:	system table
 * Return:	EFI_ST_SUCCESS for success
 */
static int setup(const efi_handle_t handle,
		 const struct efi_system_table *systable)
{
	efi_status_t ret;
	efi_handle_t *net_handle;
	efi_uintn_t num_handles;
	efi_handle_t *handles;

	boottime = systable->boottime;

	num_handles = 0;
	boottime->locate_handle_buffer(BY_PROTOCOL, &efi_ip4_config2_guid,
				       NULL, &num_handles, &handles);

	if (!num_handles) {
		efi_st_error("Failed to locate ipv4 config2 protocol\n");
		return EFI_ST_FAILURE;
	}

	for (net_handle = handles; num_handles--; net_handle++) {
		ret = boottime->open_protocol(*net_handle, &efi_ip4_config2_guid,
					      (void **)&ip4_config2, 0, 0,
					      EFI_OPEN_PROTOCOL_GET_PROTOCOL);
		if (ret != EFI_SUCCESS || !ip4_config2)
			continue;
		break; // Get first handle that supports ipv4
	}

	if (!ip4_config2) {
		efi_st_error("Failed to open ipv4 config2 protocol\n");
		return EFI_ST_FAILURE;
	}

	return EFI_ST_SUCCESS;
}

/*
 * Execute unit test.
 *
 *
 * Return:	EFI_ST_SUCCESS for success
 */
static int execute(void)
{
	efi_status_t ret;
	enum efi_ip4_config2_policy policy;
	efi_uintn_t data_size;
	struct efi_ip4_config2_manual_address manual_address;
	struct efi_ip4_config2_manual_address orig_address;
	u8 netmask[] = {255, 255, 255, 0};
	u8 ip[] = {10, 0, 0, 1};

	/* Setup may have failed */
	if (!ip4_config2) {
		efi_st_error("Setup failure, cannot proceed with test\n");
		return EFI_ST_FAILURE;
	}

	/* Set policy to static */
	policy = EFI_IP4_CONFIG2_POLICY_STATIC;
	ret = ip4_config2->set_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_POLICY,
			      sizeof(policy), (void *)&policy);
	if (ret != EFI_SUCCESS) {
		efi_st_error("Failed to set policy\n");
		return EFI_ST_FAILURE;
	}

	/* Save original ip address and netmask */
	data_size = sizeof(manual_address);
	ret = ip4_config2->get_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
			      &data_size, &orig_address);
	if (ret != EFI_SUCCESS) {
		efi_st_error("Failed to save original ip address and netmask\n");
		return EFI_ST_FAILURE;
	}

	/* Set static ip and netmask */
	memcpy(&manual_address.address, ip,
	       sizeof(struct efi_ipv4_address));
	memcpy(&manual_address.subnet_mask, netmask,
	       sizeof(struct efi_ipv4_address));
	ret = ip4_config2->set_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
			      sizeof(manual_address), &manual_address);
	if (ret != EFI_SUCCESS) {
		efi_st_error("Failed to get ip address and netmask\n");
		return EFI_ST_FAILURE;
	}

	/* Try to set interface info, this should fail */
	ret = ip4_config2->set_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO, 0, NULL);
	if (ret == EFI_SUCCESS) {
		efi_st_error("Interface info is read-only\n");
		return EFI_ST_FAILURE;
	}

	/* Get ip address and netmask and check that they match with the previously set ones */
	data_size = sizeof(manual_address);
	ret = ip4_config2->get_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
			      &data_size, &manual_address);
	if (ret != EFI_SUCCESS) {
		efi_st_error("Failed to get ip address and netmask\n");
		return EFI_ST_FAILURE;
	}
	if (memcmp(ip, &manual_address.address,
		   sizeof(struct efi_ipv4_address)) ||
	    memcmp(netmask, &manual_address.subnet_mask,
		   sizeof(struct efi_ipv4_address))) {
		efi_st_error("Ip address mismatch\n");
		return EFI_ST_FAILURE;
	}

	/* Restore original ip address and netmask */
	ret = ip4_config2->set_data(ip4_config2, EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
			      sizeof(orig_address), &orig_address);
	if (ret != EFI_SUCCESS) {
		efi_st_error("Failed to restore original ip address and netmask\n");
		return EFI_ST_FAILURE;
	}

	efi_st_printf("Efi ipconfig test execute succeeded\n");
	return EFI_ST_SUCCESS;
}

/*
 * Tear down unit test.
 *
 * Return:	EFI_ST_SUCCESS for success
 */
static int teardown(void)
{
	int exit_status = EFI_ST_SUCCESS;

	return exit_status;
}

EFI_UNIT_TEST(ipconfig) = {
	.name = "IPv4 config2 protocol",
	.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
	.setup = setup,
	.execute = execute,
	.teardown = teardown,
#ifdef CONFIG_SANDBOX
	/*
	 * Running this test on the sandbox requires setting environment
	 * variable ethact to a network interface connected to a DHCP server and
	 * ethrotate to 'no'.
	 */
	.on_request = true,
#endif
};