xref: /aosp_15_r20/external/ltp/testcases/network/lib6/in6_02.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) International Business Machines Corp., 2001
4  * Copyright (c) 2018 Petr Vorel <[email protected]>
5  * Copyright (c) Linux Test Project, 2005-2022
6  * Author: David L Stevens
7  */
8 
9 /*\
10  * [Description]
11  *
12  * IPv6 name to index and index to name function tests.
13  */
14 
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <errno.h>
19 #include <sys/socket.h>
20 #include <net/if.h>
21 
22 #include "tst_test.h"
23 
24 #define I2N_RNDCOUNT	10	/* random ints */
25 #define I2N_LOWCOUNT	10	/* sequential from 0 */
26 
27 static struct {
28 	char *name;
29 	int nonzero;
30 } test_case[] = {
31 	{ "lo", 1 },
32 	{ NULL, 1 },
33 	{ "hoser75", 0 },
34 	{ "6", 0 },
35 };
36 
37 static void setup(void);
38 static void if_nametoindex_test(void);
39 static void if_indextoname_test(void);
40 static void if_nameindex_test(void);
41 
42 static void (*testfunc[])(void) = { if_nametoindex_test, if_indextoname_test,
43 	if_nameindex_test };
44 
if_nametoindex_test(void)45 static void if_nametoindex_test(void)
46 {
47 	unsigned int i;
48 	char ifname[IF_NAMESIZE], *pifn;
49 
50 	tst_res(TINFO, "IPv6 if_nametoindex() test");
51 
52 	for (i = 0; i < ARRAY_SIZE(test_case); ++i) {
53 		if (test_case[i].name == NULL) {
54 			tst_res(TCONF, "LHOST_IFACES not defined or invalid");
55 			continue;
56 		}
57 
58 		TEST(if_nametoindex(test_case[i].name));
59 		if (!TST_RET != !test_case[i].nonzero) {
60 			tst_res(TFAIL, "if_nametoindex(%s) %ld [should be %szero]",
61 					test_case[i].name, TST_RET,
62 					test_case[i].nonzero ? "non" : "");
63 			return;
64 		}
65 		if (TST_RET) {
66 			pifn = if_indextoname(TST_RET, ifname);
67 			if (!pifn || strcmp(test_case[i].name, pifn)) {
68 				tst_res(TFAIL,
69 					"if_nametoindex(%s) %ld doesn't match if_indextoname(%ld) '%s'",
70 					test_case[i].name, TST_RET,
71 					TST_RET, pifn ? pifn : "");
72 				return;
73 			}
74 		}
75 		tst_res(TINFO, "if_nametoindex(%s) %ld",
76 			test_case[i].name, TST_RET);
77 	}
78 
79 	tst_res(TPASS, "if_nametoindex() test succeeded");
80 }
81 
sub_if_indextoname_test(unsigned int if_index)82 static int sub_if_indextoname_test(unsigned int if_index)
83 {
84 	char ifname[IF_NAMESIZE];
85 	unsigned int idx;
86 
87 	TEST((ifname == if_indextoname(if_index, ifname)));
88 	if (!TST_RET) {
89 		if (TST_ERR != ENXIO) {
90 			tst_res(TFAIL,
91 				"if_indextoname(%d) returns %ld but errno %d != ENXIO",
92 				if_index, TST_RET, TST_ERR);
93 			return 0;
94 		}
95 		tst_res(TINFO, "if_indextoname(%d) returns NULL", if_index);
96 		return 1;
97 	}
98 	/* else, a valid interface-- double check name */
99 	idx = if_nametoindex(ifname);
100 	if (idx != if_index) {
101 		tst_res(TFAIL,
102 			"if_indextoname(%u) returns '%s' but doesn't if_nametoindex(%s) returns %u",
103 			if_index, ifname, ifname, idx);
104 		return 0;
105 	}
106 	tst_res(TINFO, "if_indextoname(%d) returns '%s'", if_index, ifname);
107 	return 1;
108 }
109 
if_indextoname_test(void)110 static void if_indextoname_test(void)
111 {
112 	unsigned int i;
113 
114 	tst_res(TINFO, "IPv6 if_indextoname() test");
115 
116 	/* some low-numbered indexes-- likely to get valid interfaces here */
117 	for (i = 0; i < I2N_LOWCOUNT; ++i)
118 		if (!sub_if_indextoname_test(i))
119 			return;	/* skip the rest, if broken */
120 	/* some random ints; should mostly fail */
121 	for (i = 0; i < I2N_RNDCOUNT; ++i)
122 		if (!sub_if_indextoname_test(rand()))
123 			return;	/* skip the rest, if broken */
124 
125 	tst_res(TPASS, "if_indextoname() test succeeded");
126 }
127 
128 /*
129  * This is an ugly, linux-only solution. getrusage() doesn't support the
130  * current data segment size, so we get it out of /proc
131  */
getdatasize(void)132 static int getdatasize(void)
133 {
134 	char line[128], *p;
135 	int dsize = -1;
136 	FILE *fp;
137 
138 	fp = fopen("/proc/self/status", "r");
139 	if (fp == NULL)
140 		return -1;
141 	while (fgets(line, sizeof(line), fp)) {
142 		if (strncmp(line, "VmData:", 7) == 0) {
143 			dsize = strtol(line + 7, &p, 0);
144 			++p;	/* skip space */
145 			if (!strcmp(p, "kB"))
146 				return -1;	/* don't know units */
147 			dsize *= 1024;
148 			break;
149 		}
150 	}
151 	fclose(fp);
152 	return dsize;
153 }
154 
if_nameindex_test(void)155 static void if_nameindex_test(void)
156 {
157 	struct if_nameindex *pini;
158 	int i;
159 	char buf[IF_NAMESIZE], *p;
160 	unsigned int idx;
161 	int freenicount;
162 	int dsize_before, dsize_after;
163 
164 	tst_res(TINFO, "IPv6 if_nameindex() test");
165 
166 	pini = if_nameindex();
167 	if (pini == NULL) {
168 		tst_res(TFAIL, "if_nameindex() returns NULL, errno %d (%s)",
169 			TST_ERR, strerror(TST_ERR));
170 		return;
171 	}
172 	for (i = 0; pini[i].if_index; ++i) {
173 		p = if_indextoname(pini[i].if_index, buf);
174 		if (!p || strcmp(p, pini[i].if_name)) {
175 			tst_res(TFAIL,
176 				"if_nameindex() idx %d name '%s' but if_indextoname(%d) is '%s'",
177 				pini[i].if_index, pini[i].if_name,
178 				pini[i].if_index, p ? p : "");
179 			return;
180 		}
181 		idx = if_nametoindex(pini[i].if_name);
182 		if (idx != pini[i].if_index) {
183 			tst_res(TFAIL,
184 				"if_nameindex() idx %d name '%s' but if_indextoname(%s) is %d",
185 				pini[i].if_index, pini[i].if_name,
186 				pini[i].if_name, idx);
187 			return;
188 		}
189 		tst_res(TINFO, "if_nameindex() idx %d name '%s'",
190 				pini[i].if_index, pini[i].if_name);
191 	}
192 	if_freenameindex(pini);
193 
194 	/*
195 	 * if_freenameindex() has no error conditions; see if we run
196 	 * out of memory if we do it a lot.
197 	 */
198 	dsize_before = getdatasize();
199 	if (dsize_before < 0) {
200 		tst_brk(TBROK, "getdatasize failed: errno %d (%s)",
201 			errno, strerror(errno));
202 	}
203 
204 	/*
205 	 * we need to leak at least a page to detect a leak; 1 byte per call
206 	 * will be detected with getpagesize() calls.
207 	 */
208 	freenicount = getpagesize();
209 	for (i = 0; i < freenicount; ++i) {
210 		pini = if_nameindex();
211 		if (pini == NULL) {
212 			tst_res(TINFO,
213 				"if_freenameindex test failed if_nameindex() iteration %d", i);
214 			break;
215 		}
216 		if_freenameindex(pini);
217 	}
218 	dsize_after = getdatasize();
219 	if (dsize_after < 0) {
220 		tst_brk(TBROK, "getdatasize failed: errno %d (%s)",
221 			errno, strerror(errno));
222 	}
223 	if (dsize_after > dsize_before + getpagesize()) {
224 		tst_res(TFAIL,
225 			"if_freenameindex leaking memory (%d iterations) dsize before %d dsize after %d",
226 			i, dsize_before, dsize_after);
227 		return;
228 	}
229 	tst_res(TINFO, "if_freenameindex passed %d iterations", i);
230 
231 	tst_res(TPASS, "if_nameindex() test succeeded");
232 }
233 
setup(void)234 static void setup(void)
235 {
236 	char *ifnames = getenv("LHOST_IFACES");
237 
238 	if (!ifnames)
239 		return;
240 
241 	static char name[256];
242 	int ret;
243 
244 	ret = sscanf(ifnames, "%255s", name);
245 	if (ret == -1)
246 		return;
247 
248 	tst_res(TINFO, "get interface name from LHOST_IFACES: '%s'", name);
249 	test_case[1].name = name;
250 }
251 
do_test(unsigned int i)252 static void do_test(unsigned int i)
253 {
254 	testfunc[i]();
255 }
256 
257 static struct tst_test test = {
258 	.tcnt = ARRAY_SIZE(testfunc),
259 	.setup = setup,
260 	.test = do_test,
261 };
262