1 /*
2 * Check decoding of struct msghdr ancillary data.
3 *
4 * Copyright (c) 2016 Dmitry V. Levin <ldv@strace.io>
5 * Copyright (c) 2016-2023 The strace developers.
6 * All rights reserved.
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "tests.h"
12 #include <errno.h>
13 #include <limits.h>
14 #include <stddef.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <sys/socket.h>
19 #include <net/if.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22
23 #include "kernel_time_types.h"
24 #include "kernel_timeval.h"
25 #include "kernel_old_timespec.h"
26
27 #include "xlat.h"
28 #define XLAT_MACROS_ONLY
29 #include "xlat/ip_cmsg_types.h"
30 #include "xlat/sock_options.h"
31 #include "xlat/scmvals.h"
32 #undef XLAT_MACROS_ONLY
33
34 #ifndef SOL_IP
35 # define SOL_IP 0
36 #endif
37 #ifndef SOL_TCP
38 # define SOL_TCP 6
39 #endif
40
41 static struct cmsghdr *
42 get_cmsghdr(void *const page, const size_t len)
43 {
44 return page - CMSG_ALIGN(len);
45 }
46
47 static void
48 print_fds(const struct cmsghdr *const cmsg, const size_t cmsg_len)
49 {
50 size_t nfd = cmsg_len > CMSG_LEN(0)
51 ? (cmsg_len - CMSG_LEN(0)) / sizeof(int) : 0;
52 if (!nfd)
53 return;
54
55 printf(", cmsg_data=[");
56 int *fdp = (int *) CMSG_DATA(cmsg);
57 for (size_t i = 0; i < nfd; ++i) {
58 if (i)
59 printf(", ");
60 #if !VERBOSE
61 if (i >= DEFAULT_STRLEN) {
62 printf("...");
63 break;
64 }
65 #endif
66 printf("%d", fdp[i]);
67 }
68 printf("]");
69 }
70
71 static void
72 test_scm_rights1(struct msghdr *const mh,
73 const size_t msg_controllen,
74 void *const page,
75 const void *const src,
76 const size_t cmsg_len)
77 {
78 const size_t aligned_cms_len =
79 cmsg_len > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len) : CMSG_LEN(0);
80 if (cmsg_len >= CMSG_LEN(0)
81 && aligned_cms_len + CMSG_LEN(0) <= msg_controllen)
82 return;
83
84 struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen);
85
86 if (msg_controllen >= offsetofend(struct cmsghdr, cmsg_len))
87 cmsg->cmsg_len = cmsg_len;
88 if (msg_controllen >= offsetofend(struct cmsghdr, cmsg_level))
89 cmsg->cmsg_level = SOL_SOCKET;
90 if (msg_controllen >= offsetofend(struct cmsghdr, cmsg_type))
91 cmsg->cmsg_type = SCM_RIGHTS;
92
93 size_t src_len =
94 cmsg_len < msg_controllen ? cmsg_len : msg_controllen;
95 if (src_len > CMSG_LEN(0))
96 memcpy(CMSG_DATA(cmsg), src, src_len - CMSG_LEN(0));
97
98 mh->msg_control = cmsg;
99 mh->msg_controllen = msg_controllen;
100
101 int rc = sendmsg(-1, mh, 0);
102 int saved_errno = errno;
103
104 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
105 ", msg_iovlen=0");
106 if (msg_controllen < CMSG_LEN(0)) {
107 if (msg_controllen)
108 printf(", msg_control=%p", cmsg);
109 } else {
110 printf(", msg_control=[{cmsg_len=%lu, cmsg_level=SOL_SOCKET"
111 ", cmsg_type=SCM_RIGHTS", (unsigned long) cmsg_len);
112 print_fds(cmsg, src_len);
113 printf("}");
114 if (aligned_cms_len < msg_controllen)
115 printf(", ... /* %p */", (void *) cmsg + aligned_cms_len);
116 printf("]");
117 }
118
119 errno = saved_errno;
120 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
121 (unsigned long) msg_controllen, rc, errno2name());
122 }
123
124 static void
125 test_scm_rights2(struct msghdr *const mh,
126 const size_t msg_controllen,
127 void *const page,
128 const int *const *const src,
129 const size_t *const cmsg_len)
130 {
131 const size_t aligned_cms_len[2] = {
132 cmsg_len[0] > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len[0]) : CMSG_LEN(0),
133 cmsg_len[1] > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len[1]) : CMSG_LEN(0)
134 };
135 if (cmsg_len[0] < CMSG_LEN(0)
136 || aligned_cms_len[0] + CMSG_LEN(0) > msg_controllen
137 || aligned_cms_len[0] + aligned_cms_len[1] + CMSG_LEN(0) <= msg_controllen)
138 return;
139
140 struct cmsghdr *const cmsg[2] = {
141 get_cmsghdr(page, msg_controllen),
142 (void *) get_cmsghdr(page, msg_controllen) + aligned_cms_len[0]
143 };
144 cmsg[0]->cmsg_len = cmsg_len[0];
145 cmsg[0]->cmsg_level = SOL_SOCKET;
146 cmsg[0]->cmsg_type = SCM_RIGHTS;
147 if (cmsg_len[0] > CMSG_LEN(0))
148 memcpy(CMSG_DATA(cmsg[0]), src[0], cmsg_len[0] - CMSG_LEN(0));
149
150 const size_t msg_controllen1 = msg_controllen - aligned_cms_len[0];
151 if (msg_controllen1 >= offsetofend(struct cmsghdr, cmsg_len))
152 cmsg[1]->cmsg_len = cmsg_len[1];
153 if (msg_controllen >= offsetofend(struct cmsghdr, cmsg_level))
154 cmsg[1]->cmsg_level = SOL_SOCKET;
155 if (msg_controllen >= offsetofend(struct cmsghdr, cmsg_type))
156 cmsg[1]->cmsg_type = SCM_RIGHTS;
157 size_t src1_len =
158 cmsg_len[1] < msg_controllen1 ? cmsg_len[1] : msg_controllen1;
159 if (src1_len > CMSG_LEN(0))
160 memcpy(CMSG_DATA(cmsg[1]), src[1], src1_len - CMSG_LEN(0));
161
162 mh->msg_control = cmsg[0];
163 mh->msg_controllen = msg_controllen;
164
165 int rc = sendmsg(-1, mh, 0);
166 int saved_errno = errno;
167
168 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
169 ", msg_iovlen=0, msg_control=[{cmsg_len=%lu"
170 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
171 (unsigned long) cmsg_len[0]);
172 print_fds(cmsg[0], cmsg_len[0]);
173 printf("}, {cmsg_len=%lu, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
174 (unsigned long) cmsg_len[1]);
175 print_fds(cmsg[1], src1_len);
176 printf("}");
177 if (aligned_cms_len[1] < msg_controllen1)
178 printf(", ... /* %p */", (void *) cmsg[1] + aligned_cms_len[1]);
179 printf("]");
180
181 errno = saved_errno;
182 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
183 (unsigned long) msg_controllen, rc, errno2name());
184 }
185
186 static void
187 test_scm_rights3(struct msghdr *const mh, void *const page, const size_t nfds)
188 {
189 const size_t len = CMSG_SPACE(sizeof(int) * nfds);
190 struct cmsghdr *cmsg = get_cmsghdr(page, len);
191
192 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * nfds);
193 cmsg->cmsg_level = SOL_SOCKET;
194 cmsg->cmsg_type = SCM_RIGHTS;
195 int *fdp = (int *) CMSG_DATA(cmsg);
196 for (size_t i = 0; i < nfds; ++i)
197 fdp[i] = i;
198
199 mh->msg_control = cmsg;
200 mh->msg_controllen = len;
201
202 int rc = sendmsg(-1, mh, 0);
203 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
204 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
205 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
206 (unsigned) cmsg->cmsg_len);
207 print_fds(cmsg, cmsg->cmsg_len);
208 printf("}], msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
209 (unsigned long) len, rc, errno2name());
210 }
211
212 static void
213 test_scm_timestamp_old(struct msghdr *const mh, void *const page)
214 {
215 static const kernel_old_timeval_t tv = {
216 .tv_sec = 123456789,
217 .tv_usec = 987654
218 };
219 size_t len = CMSG_SPACE(sizeof(tv));
220 struct cmsghdr *cmsg = get_cmsghdr(page, len);
221
222 cmsg->cmsg_len = CMSG_LEN(sizeof(tv));
223 cmsg->cmsg_level = SOL_SOCKET;
224 cmsg->cmsg_type = SO_TIMESTAMP_OLD;
225 memcpy(CMSG_DATA(cmsg), &tv, sizeof(tv));
226
227 mh->msg_control = cmsg;
228 mh->msg_controllen = len;
229
230 int rc = sendmsg(-1, mh, 0);
231 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
232 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
233 ", cmsg_level=SOL_SOCKET, cmsg_type=SO_TIMESTAMP_OLD"
234 ", cmsg_data={tv_sec=%lld, tv_usec=%llu}}]"
235 ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
236 (unsigned) cmsg->cmsg_len,
237 (long long) tv.tv_sec, zero_extend_signed_to_ull(tv.tv_usec),
238 (unsigned long) len, rc, errno2name());
239
240 len = CMSG_SPACE(sizeof(tv) - sizeof(long));
241 cmsg = get_cmsghdr(page, len);
242
243 cmsg->cmsg_len = CMSG_LEN(sizeof(tv) - sizeof(long));
244 cmsg->cmsg_level = SOL_SOCKET;
245 cmsg->cmsg_type = SO_TIMESTAMP_OLD;
246
247 mh->msg_control = cmsg;
248 mh->msg_controllen = len;
249
250 rc = sendmsg(-1, mh, 0);
251 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
252 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
253 ", cmsg_level=SOL_SOCKET, cmsg_type=SO_TIMESTAMP_OLD, cmsg_data=???}]"
254 ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
255 (unsigned) cmsg->cmsg_len,
256 (unsigned long) len, rc, errno2name());
257 }
258
259 static void
260 test_scm_timestampns_old(struct msghdr *const mh, void *const page)
261 {
262 static const kernel_old_timespec_t ts = {
263 .tv_sec = 123456789,
264 .tv_nsec = 987654321
265 };
266 size_t len = CMSG_SPACE(sizeof(ts));
267 struct cmsghdr *cmsg = get_cmsghdr(page, len);
268
269 cmsg->cmsg_len = CMSG_LEN(sizeof(ts));
270 cmsg->cmsg_level = SOL_SOCKET;
271 cmsg->cmsg_type = SO_TIMESTAMPNS_OLD;
272 memcpy(CMSG_DATA(cmsg), &ts, sizeof(ts));
273
274 mh->msg_control = cmsg;
275 mh->msg_controllen = len;
276
277 int rc = sendmsg(-1, mh, 0);
278 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
279 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
280 ", cmsg_level=SOL_SOCKET, cmsg_type=SO_TIMESTAMPNS_OLD"
281 ", cmsg_data={tv_sec=%lld, tv_nsec=%llu}}]"
282 ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
283 (unsigned) cmsg->cmsg_len,
284 (long long) ts.tv_sec, zero_extend_signed_to_ull(ts.tv_nsec),
285 (unsigned long) len, rc, errno2name());
286
287 len = CMSG_SPACE(sizeof(ts) - sizeof(long));
288 cmsg = get_cmsghdr(page, len);
289
290 cmsg->cmsg_len = CMSG_LEN(sizeof(ts) - sizeof(long));
291 cmsg->cmsg_level = SOL_SOCKET;
292 cmsg->cmsg_type = SO_TIMESTAMPNS_OLD;
293
294 mh->msg_control = cmsg;
295 mh->msg_controllen = len;
296
297 rc = sendmsg(-1, mh, 0);
298 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
299 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
300 ", cmsg_level=SOL_SOCKET, cmsg_type=SO_TIMESTAMPNS_OLD"
301 ", cmsg_data=???}]"
302 ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
303 (unsigned) cmsg->cmsg_len,
304 (unsigned long) len, rc, errno2name());
305 }
306
307 static void
308 test_scm_timestamping_old(struct msghdr *const mh, void *const page)
309 {
310 static const kernel_old_timespec_t ts[] = {
311 { .tv_sec = 123456789, .tv_nsec = 987654321 },
312 { .tv_sec = 123456790, .tv_nsec = 987654320 },
313 { .tv_sec = 123456791, .tv_nsec = 987654319 }
314 };
315 size_t len = CMSG_SPACE(sizeof(ts));
316 struct cmsghdr *cmsg = get_cmsghdr(page, len);
317
318 cmsg->cmsg_len = CMSG_LEN(sizeof(ts));
319 cmsg->cmsg_level = SOL_SOCKET;
320 cmsg->cmsg_type = SO_TIMESTAMPING_OLD;
321 memcpy(CMSG_DATA(cmsg), ts, sizeof(ts));
322
323 mh->msg_control = cmsg;
324 mh->msg_controllen = len;
325
326 int rc = sendmsg(-1, mh, 0);
327 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
328 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
329 ", cmsg_level=SOL_SOCKET, cmsg_type=SO_TIMESTAMPING_OLD"
330 ", cmsg_data=[{tv_sec=%lld, tv_nsec=%llu}"
331 ", {tv_sec=%lld, tv_nsec=%llu}, {tv_sec=%lld, tv_nsec=%llu}]}]"
332 ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
333 (unsigned) cmsg->cmsg_len, (long long) ts[0].tv_sec,
334 zero_extend_signed_to_ull(ts[0].tv_nsec),
335 (long long) ts[1].tv_sec,
336 zero_extend_signed_to_ull(ts[1].tv_nsec),
337 (long long) ts[2].tv_sec,
338 zero_extend_signed_to_ull(ts[2].tv_nsec),
339 (unsigned long) len, rc, errno2name());
340
341 len = CMSG_SPACE(sizeof(ts) - sizeof(long));
342 cmsg = get_cmsghdr(page, len);
343
344 cmsg->cmsg_len = CMSG_LEN(sizeof(ts) - sizeof(long));
345 cmsg->cmsg_level = SOL_SOCKET;
346 cmsg->cmsg_type = SO_TIMESTAMPING_OLD;
347
348 mh->msg_control = cmsg;
349 mh->msg_controllen = len;
350
351 rc = sendmsg(-1, mh, 0);
352 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
353 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
354 ", cmsg_level=SOL_SOCKET, cmsg_type=SO_TIMESTAMPING_OLD"
355 ", cmsg_data=???}]"
356 ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
357 (unsigned) cmsg->cmsg_len,
358 (unsigned long) len, rc, errno2name());
359 }
360
361 static void
362 test_scm_timestamp_new(struct msghdr *const mh, void *const page)
363 {
364 static const struct __kernel_sock_timeval tv = {
365 .tv_sec = 0xdefaceddeadbeef,
366 .tv_usec = 0xdec0dedcafef00d
367 };
368 size_t len = CMSG_SPACE(sizeof(tv));
369 struct cmsghdr *cmsg = get_cmsghdr(page, len);
370
371 cmsg->cmsg_len = CMSG_LEN(sizeof(tv));
372 cmsg->cmsg_level = SOL_SOCKET;
373 cmsg->cmsg_type = SO_TIMESTAMP_NEW;
374 memcpy(CMSG_DATA(cmsg), &tv, sizeof(tv));
375
376 mh->msg_control = cmsg;
377 mh->msg_controllen = len;
378
379 int rc = sendmsg(-1, mh, 0);
380 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
381 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
382 ", cmsg_level=SOL_SOCKET, cmsg_type=SO_TIMESTAMP_NEW"
383 ", cmsg_data={tv_sec=%lld, tv_usec=%llu}}]"
384 ", msg_controllen=%lu, msg_flags=0}, 0) = %s\n",
385 (unsigned) cmsg->cmsg_len,
386 (long long) tv.tv_sec, zero_extend_signed_to_ull(tv.tv_usec),
387 (unsigned long) len, sprintrc(rc));
388
389 len = CMSG_SPACE(sizeof(tv) - sizeof(long));
390 cmsg = get_cmsghdr(page, len);
391
392 cmsg->cmsg_len = CMSG_LEN(sizeof(tv) - sizeof(long));
393 cmsg->cmsg_level = SOL_SOCKET;
394 cmsg->cmsg_type = SO_TIMESTAMP_NEW;
395
396 mh->msg_control = cmsg;
397 mh->msg_controllen = len;
398
399 rc = sendmsg(-1, mh, 0);
400 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
401 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
402 ", cmsg_level=SOL_SOCKET, cmsg_type=SO_TIMESTAMP_NEW, cmsg_data=???}]"
403 ", msg_controllen=%lu, msg_flags=0}, 0) = %s\n",
404 (unsigned) cmsg->cmsg_len,
405 (unsigned long) len, sprintrc(rc));
406 }
407
408 static void
409 test_scm_timestampns_new(struct msghdr *const mh, void *const page)
410 {
411 static const struct __kernel_timespec ts = {
412 .tv_sec = 0xdefaceddeadbeef,
413 .tv_nsec = 0xdec0dedcafef00d
414 };
415 size_t len = CMSG_SPACE(sizeof(ts));
416 struct cmsghdr *cmsg = get_cmsghdr(page, len);
417
418 cmsg->cmsg_len = CMSG_LEN(sizeof(ts));
419 cmsg->cmsg_level = SOL_SOCKET;
420 cmsg->cmsg_type = SO_TIMESTAMPNS_NEW;
421 memcpy(CMSG_DATA(cmsg), &ts, sizeof(ts));
422
423 mh->msg_control = cmsg;
424 mh->msg_controllen = len;
425
426 int rc = sendmsg(-1, mh, 0);
427 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
428 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
429 ", cmsg_level=SOL_SOCKET, cmsg_type=SO_TIMESTAMPNS_NEW"
430 ", cmsg_data={tv_sec=%lld, tv_nsec=%llu}}]"
431 ", msg_controllen=%lu, msg_flags=0}, 0) = %s\n",
432 (unsigned) cmsg->cmsg_len,
433 (long long) ts.tv_sec, zero_extend_signed_to_ull(ts.tv_nsec),
434 (unsigned long) len, sprintrc(rc));
435
436 len = CMSG_SPACE(sizeof(ts) - sizeof(long));
437 cmsg = get_cmsghdr(page, len);
438
439 cmsg->cmsg_len = CMSG_LEN(sizeof(ts) - sizeof(long));
440 cmsg->cmsg_level = SOL_SOCKET;
441 cmsg->cmsg_type = SO_TIMESTAMPNS_NEW;
442
443 mh->msg_control = cmsg;
444 mh->msg_controllen = len;
445
446 rc = sendmsg(-1, mh, 0);
447 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
448 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
449 ", cmsg_level=SOL_SOCKET, cmsg_type=SO_TIMESTAMPNS_NEW"
450 ", cmsg_data=???}]"
451 ", msg_controllen=%lu, msg_flags=0}, 0) = %s\n",
452 (unsigned) cmsg->cmsg_len,
453 (unsigned long) len, sprintrc(rc));
454 }
455
456 static void
457 test_scm_timestamping_new(struct msghdr *const mh, void *const page)
458 {
459 static const struct __kernel_timespec ts[] = {
460 { .tv_sec = 0xdeface0deadbef1, .tv_nsec = 0xdec0de2cafef0d3 },
461 { .tv_sec = 0xdeface4deadbef5, .tv_nsec = 0xdec0de6cafef0d7 },
462 { .tv_sec = 0xdeface8deadbef9, .tv_nsec = 0xdec0dedcafef00d }
463 };
464 size_t len = CMSG_SPACE(sizeof(ts));
465 struct cmsghdr *cmsg = get_cmsghdr(page, len);
466
467 cmsg->cmsg_len = CMSG_LEN(sizeof(ts));
468 cmsg->cmsg_level = SOL_SOCKET;
469 cmsg->cmsg_type = SO_TIMESTAMPING_NEW;
470 memcpy(CMSG_DATA(cmsg), ts, sizeof(ts));
471
472 mh->msg_control = cmsg;
473 mh->msg_controllen = len;
474
475 int rc = sendmsg(-1, mh, 0);
476 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
477 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
478 ", cmsg_level=SOL_SOCKET, cmsg_type=SO_TIMESTAMPING_NEW"
479 ", cmsg_data=[{tv_sec=%lld, tv_nsec=%llu}"
480 ", {tv_sec=%lld, tv_nsec=%llu}, {tv_sec=%lld, tv_nsec=%llu}]}]"
481 ", msg_controllen=%lu, msg_flags=0}, 0) = %s\n",
482 (unsigned) cmsg->cmsg_len, (long long) ts[0].tv_sec,
483 zero_extend_signed_to_ull(ts[0].tv_nsec),
484 (long long) ts[1].tv_sec,
485 zero_extend_signed_to_ull(ts[1].tv_nsec),
486 (long long) ts[2].tv_sec,
487 zero_extend_signed_to_ull(ts[2].tv_nsec),
488 (unsigned long) len, sprintrc(rc));
489
490 len = CMSG_SPACE(sizeof(ts) - sizeof(long));
491 cmsg = get_cmsghdr(page, len);
492
493 cmsg->cmsg_len = CMSG_LEN(sizeof(ts) - sizeof(long));
494 cmsg->cmsg_level = SOL_SOCKET;
495 cmsg->cmsg_type = SO_TIMESTAMPING_NEW;
496
497 mh->msg_control = cmsg;
498 mh->msg_controllen = len;
499
500 rc = sendmsg(-1, mh, 0);
501 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
502 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
503 ", cmsg_level=SOL_SOCKET, cmsg_type=SO_TIMESTAMPING_NEW"
504 ", cmsg_data=???}]"
505 ", msg_controllen=%lu, msg_flags=0}, 0) = %s\n",
506 (unsigned) cmsg->cmsg_len,
507 (unsigned long) len, sprintrc(rc));
508 }
509
510 static void
511 print_security(const struct cmsghdr *const cmsg, const size_t cmsg_len)
512 {
513 int n = cmsg_len > CMSG_LEN(0) ? cmsg_len - CMSG_LEN(0) : 0;
514 if (!n)
515 return;
516
517 printf(", cmsg_data=\"%.*s\"", n, CMSG_DATA(cmsg));
518 }
519
520 static void
521 test_scm_security(struct msghdr *const mh,
522 const size_t msg_controllen,
523 void *const page,
524 const void *const src,
525 const size_t cmsg_len,
526 const int cmsg_level,
527 const char *const cmsg_level_str)
528 {
529 const size_t aligned_cms_len =
530 cmsg_len > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len) : CMSG_LEN(0);
531 if (cmsg_len >= CMSG_LEN(0)
532 && aligned_cms_len + CMSG_LEN(0) <= msg_controllen)
533 return;
534
535 struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen);
536
537 cmsg->cmsg_len = cmsg_len;
538 cmsg->cmsg_level = cmsg_level;
539 cmsg->cmsg_type = SCM_SECURITY;
540
541 size_t src_len =
542 cmsg_len < msg_controllen ? cmsg_len : msg_controllen;
543 if (src_len > CMSG_LEN(0))
544 memcpy(CMSG_DATA(cmsg), src, src_len - CMSG_LEN(0));
545
546 mh->msg_control = cmsg;
547 mh->msg_controllen = msg_controllen;
548
549 int rc = sendmsg(-1, mh, 0);
550 int saved_errno = errno;
551
552 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
553 ", msg_iovlen=0, msg_control=[{cmsg_len=%lu, cmsg_level=%s"
554 ", cmsg_type=SCM_SECURITY",
555 (unsigned long) cmsg_len, cmsg_level_str);
556 print_security(cmsg, src_len);
557 printf("}");
558 if (aligned_cms_len < msg_controllen)
559 printf(", ... /* %p */", (void *) cmsg + aligned_cms_len);
560 printf("]");
561
562 errno = saved_errno;
563 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
564 (unsigned long) msg_controllen, rc, errno2name());
565 }
566
567 static void
568 test_unknown_type(struct msghdr *const mh,
569 void *const page,
570 const int cmsg_level,
571 const char *const cmsg_level_str,
572 const char *const cmsg_type_str)
573 {
574 struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0));
575
576 cmsg->cmsg_len = CMSG_LEN(0);
577 cmsg->cmsg_level = cmsg_level;
578 cmsg->cmsg_type = 0xfacefeed;
579
580 mh->msg_control = cmsg;
581 mh->msg_controllen = cmsg->cmsg_len;
582
583 int rc = sendmsg(-1, mh, 0);
584 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
585 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=%s"
586 ", cmsg_type=%#x /* %s */}], msg_controllen=%u, msg_flags=0}"
587 ", 0) = %d %s (%m)\n",
588 (unsigned) cmsg->cmsg_len, cmsg_level_str, cmsg->cmsg_type,
589 cmsg_type_str, (unsigned) mh->msg_controllen, rc, errno2name());
590 }
591
592 static void
593 test_sol_socket(struct msghdr *const mh, void *const page)
594 {
595 static const int fds0[] = { -10, -11, -12, -13 };
596 static const int fds1[] = { -15, -16, -17, -18 };
597 size_t max_msg_controllen;
598
599 max_msg_controllen = CMSG_SPACE(sizeof(fds0)) + sizeof(*fds0) - 1;
600 for (size_t msg_controllen = 0;
601 msg_controllen <= max_msg_controllen;
602 msg_controllen++) {
603 for (size_t cmsg_len = 0;
604 cmsg_len <= msg_controllen + CMSG_LEN(0);
605 cmsg_len++) {
606 test_scm_rights1(mh, msg_controllen,
607 page, fds0, cmsg_len);
608 }
609 }
610
611 max_msg_controllen =
612 CMSG_SPACE(sizeof(fds0)) + CMSG_SPACE(sizeof(fds1)) +
613 sizeof(*fds0) - 1;
614 for (size_t msg_controllen = CMSG_LEN(0) * 2;
615 msg_controllen <= max_msg_controllen;
616 msg_controllen++) {
617 static const int *const fdps[] = { fds0, fds1 };
618 size_t cmsg_len[2];
619
620 for (cmsg_len[0] = CMSG_LEN(0);
621 CMSG_ALIGN(cmsg_len[0]) + CMSG_LEN(0) <= msg_controllen
622 && CMSG_ALIGN(cmsg_len[0]) <= CMSG_SPACE(sizeof(fds0));
623 cmsg_len[0]++) {
624 const size_t msg_controllen1 =
625 msg_controllen - CMSG_ALIGN(cmsg_len[0]);
626
627 for (cmsg_len[1] = 0;
628 cmsg_len[1] <= msg_controllen1 + CMSG_LEN(0);
629 cmsg_len[1]++) {
630 test_scm_rights2(mh, msg_controllen,
631 page, fdps, cmsg_len);
632 }
633 }
634 }
635
636 static const char text[16] = "0123456789abcdef";
637 max_msg_controllen = CMSG_SPACE(sizeof(text)) + CMSG_LEN(0) - 1;
638 for (size_t msg_controllen = CMSG_LEN(0);
639 msg_controllen <= max_msg_controllen;
640 msg_controllen++) {
641 for (size_t cmsg_len = 0;
642 cmsg_len <= msg_controllen + CMSG_LEN(0)
643 && cmsg_len <= CMSG_LEN(sizeof(text));
644 cmsg_len++) {
645 test_scm_security(mh, msg_controllen,
646 page, text, cmsg_len,
647 ARG_STR(SOL_SOCKET));
648 }
649 }
650
651 test_scm_rights3(mh, page, DEFAULT_STRLEN - 1);
652 test_scm_rights3(mh, page, DEFAULT_STRLEN);
653 test_scm_rights3(mh, page, DEFAULT_STRLEN + 1);
654
655 test_scm_timestamp_old(mh, page);
656 test_scm_timestampns_old(mh, page);
657 test_scm_timestamping_old(mh, page);
658 test_scm_timestamp_new(mh, page);
659 test_scm_timestampns_new(mh, page);
660 test_scm_timestamping_new(mh, page);
661
662 test_unknown_type(mh, page, ARG_STR(SOL_SOCKET), "SCM_???");
663 }
664
665 static void
666 test_ip_pktinfo(struct msghdr *const mh, void *const page,
667 const int cmsg_type, const char *const cmsg_type_str)
668 {
669 const unsigned int len = CMSG_SPACE(sizeof(struct in_pktinfo));
670 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
671
672 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
673 cmsg->cmsg_level = SOL_IP;
674 cmsg->cmsg_type = cmsg_type;
675
676 struct in_pktinfo *const info = (struct in_pktinfo *) CMSG_DATA(cmsg);
677 info->ipi_ifindex = ifindex_lo();
678 info->ipi_spec_dst.s_addr = inet_addr("1.2.3.4");
679 info->ipi_addr.s_addr = inet_addr("5.6.7.8");
680
681 mh->msg_control = cmsg;
682 mh->msg_controllen = len;
683
684 int rc = sendmsg(-1, mh, 0);
685 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
686 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP"
687 ", cmsg_type=%s, cmsg_data={ipi_ifindex=%s"
688 ", ipi_spec_dst=inet_addr(\"%s\")"
689 ", ipi_addr=inet_addr(\"%s\")}}]"
690 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
691 (unsigned) cmsg->cmsg_len, cmsg_type_str,
692 IFINDEX_LO_STR, "1.2.3.4", "5.6.7.8", len, rc, errno2name());
693 }
694
695 static void
696 test_ip_uint(struct msghdr *const mh, void *const page,
697 const int cmsg_type, const char *const cmsg_type_str)
698 {
699 const unsigned int len = CMSG_SPACE(sizeof(int));
700 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
701
702 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
703 cmsg->cmsg_level = SOL_IP;
704 cmsg->cmsg_type = cmsg_type;
705
706 unsigned int *u = (void *) CMSG_DATA(cmsg);
707 *u = 0xfacefeed;
708
709 mh->msg_control = cmsg;
710 mh->msg_controllen = len;
711
712 int rc = sendmsg(-1, mh, 0);
713 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
714 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
715 ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[%u]}]"
716 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
717 (unsigned) cmsg->cmsg_len, cmsg_type_str, *u, len,
718 rc, errno2name());
719 }
720
721 static void
722 test_ip_uint8_t(struct msghdr *const mh, void *const page,
723 const int cmsg_type, const char *const cmsg_type_str)
724 {
725 const unsigned int len = CMSG_SPACE(1);
726 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
727
728 cmsg->cmsg_len = CMSG_LEN(1);
729 cmsg->cmsg_level = SOL_IP;
730 cmsg->cmsg_type = cmsg_type;
731 *CMSG_DATA(cmsg) = 'A';
732
733 mh->msg_control = cmsg;
734 mh->msg_controllen = len;
735
736 int rc = sendmsg(-1, mh, 0);
737 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
738 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
739 ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[%#x]}]"
740 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
741 (unsigned) cmsg->cmsg_len, cmsg_type_str,
742 (unsigned) (uint8_t) 'A', len, rc, errno2name());
743 }
744
745 static void
746 print_ip_opts(const void *const cmsg_data, const unsigned int data_len)
747 {
748 const unsigned char *const opts = cmsg_data;
749 for (unsigned int i = 0; i < data_len; ++i) {
750 if (i)
751 printf(", ");
752 #if !VERBOSE
753 if (i >= DEFAULT_STRLEN) {
754 printf("...");
755 break;
756 }
757 #endif
758 printf("0x%02x", opts[i]);
759 }
760 }
761
762 static void
763 test_ip_opts(struct msghdr *const mh, void *const page,
764 const int cmsg_type, const char *const cmsg_type_str,
765 const unsigned int opts_len)
766 {
767 unsigned int len = CMSG_SPACE(opts_len);
768 struct cmsghdr *cmsg = get_cmsghdr(page, len);
769
770 cmsg->cmsg_len = CMSG_LEN(opts_len);
771 cmsg->cmsg_level = SOL_IP;
772 cmsg->cmsg_type = cmsg_type;
773 for (unsigned int i = 0; i < opts_len; ++i)
774 CMSG_DATA(cmsg)[i] = 'A' + i;
775
776 mh->msg_control = cmsg;
777 mh->msg_controllen = len;
778
779 int rc = sendmsg(-1, mh, 0);
780 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
781 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
782 ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[",
783 (unsigned) cmsg->cmsg_len, cmsg_type_str);
784 print_ip_opts(CMSG_DATA(cmsg), opts_len);
785 printf("]}], msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
786 len, rc, errno2name());
787 }
788
789 #ifdef IP_RECVERR
790 struct sock_ee {
791 uint32_t ee_errno;
792 uint8_t ee_origin;
793 uint8_t ee_type;
794 uint8_t ee_code;
795 uint8_t ee_pad;
796 uint32_t ee_info;
797 uint32_t ee_data;
798 struct sockaddr_in offender;
799 };
800
801 static void
802 test_ip_recverr(struct msghdr *const mh, void *const page,
803 const int cmsg_type, const char *const cmsg_type_str)
804 {
805 const unsigned int len = CMSG_SPACE(sizeof(struct sock_ee));
806 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
807
808 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sock_ee));
809 cmsg->cmsg_level = SOL_IP;
810 cmsg->cmsg_type = cmsg_type;
811
812 struct sock_ee *const e = (struct sock_ee *) CMSG_DATA(cmsg);
813 e->ee_errno = 0xdeadbeef;
814 e->ee_origin = 2;
815 e->ee_type = 3;
816 e->ee_code = 4;
817 e->ee_info = 0xfacefeed;
818 e->ee_data = 0xbadc0ded;
819 e->offender.sin_family = AF_INET,
820 e->offender.sin_port = htons(12345),
821 e->offender.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
822
823 mh->msg_control = cmsg;
824 mh->msg_controllen = len;
825
826 int rc = sendmsg(-1, mh, 0);
827 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
828 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP"
829 ", cmsg_type=%s, cmsg_data={ee_errno=%u, ee_origin=%u"
830 ", ee_type=%u, ee_code=%u, ee_info=%u, ee_data=%u"
831 ", offender={sa_family=AF_INET, sin_port=htons(%hu)"
832 ", sin_addr=inet_addr(\"127.0.0.1\")}}}]"
833 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
834 (unsigned) cmsg->cmsg_len, cmsg_type_str,
835 e->ee_errno, e->ee_origin, e->ee_type,
836 e->ee_code, e->ee_info, e->ee_data,
837 ntohs(e->offender.sin_port),
838 len, rc, errno2name());
839 }
840 #endif
841
842 #ifdef IP_ORIGDSTADDR
843 static void
844 test_ip_origdstaddr(struct msghdr *const mh, void *const page,
845 const int cmsg_type, const char *const cmsg_type_str)
846 {
847 const unsigned int len = CMSG_SPACE(sizeof(struct sockaddr_in));
848 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
849
850 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sockaddr_in));
851 cmsg->cmsg_level = SOL_IP;
852 cmsg->cmsg_type = cmsg_type;
853
854 struct sockaddr_in *const sin = (struct sockaddr_in *) CMSG_DATA(cmsg);
855 sin->sin_family = AF_INET,
856 sin->sin_port = htons(12345),
857 sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
858
859 mh->msg_control = cmsg;
860 mh->msg_controllen = len;
861
862 int rc = sendmsg(-1, mh, 0);
863 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
864 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP"
865 ", cmsg_type=%s, cmsg_data={sa_family=AF_INET"
866 ", sin_port=htons(%hu), sin_addr=inet_addr(\"127.0.0.1\")}}]"
867 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
868 (unsigned) cmsg->cmsg_len, cmsg_type_str,
869 ntohs(sin->sin_port), len, rc, errno2name());
870 }
871 #endif
872
873 #ifdef IP_PROTOCOL
874 static void
875 test_ip_protocol(struct msghdr *const mh, void *const page,
876 const int cmsg_type, const char *const cmsg_type_str)
877 {
878 const unsigned int len = CMSG_SPACE(sizeof(int));
879 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
880
881 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
882 cmsg->cmsg_level = SOL_IP;
883 cmsg->cmsg_type = cmsg_type;
884
885 unsigned int *u = (void *) CMSG_DATA(cmsg);
886 *u = IPPROTO_RAW;
887
888 mh->msg_control = cmsg;
889 mh->msg_controllen = len;
890
891 int rc = sendmsg(-1, mh, 0);
892 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
893 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
894 ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[%s]}]"
895 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
896 (unsigned) cmsg->cmsg_len, cmsg_type_str, "IPPROTO_RAW", len,
897 rc, errno2name());
898 }
899 #endif
900
901 static void
902 test_sol_ip(struct msghdr *const mh, void *const page)
903 {
904 test_ip_pktinfo(mh, page, ARG_STR(IP_PKTINFO));
905 test_ip_uint(mh, page, ARG_STR(IP_TTL));
906 test_ip_uint8_t(mh, page, ARG_STR(IP_TOS));
907 test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 1);
908 test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 2);
909 test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 3);
910 test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 4);
911 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 5);
912 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 6);
913 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 7);
914 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 8);
915 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), DEFAULT_STRLEN - 1);
916 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), DEFAULT_STRLEN);
917 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), DEFAULT_STRLEN + 1);
918 #ifdef IP_RECVERR
919 test_ip_recverr(mh, page, ARG_STR(IP_RECVERR));
920 #endif
921 #ifdef IP_ORIGDSTADDR
922 test_ip_origdstaddr(mh, page, ARG_STR(IP_ORIGDSTADDR));
923 #endif
924 #ifdef IP_CHECKSUM
925 test_ip_uint(mh, page, ARG_STR(IP_CHECKSUM));
926 #endif
927 #ifdef IP_PROTOCOL
928 test_ip_protocol(mh, page, ARG_STR(IP_PROTOCOL));
929 #endif
930 test_scm_security(mh, CMSG_LEN(0), page, 0, CMSG_LEN(0),
931 ARG_STR(SOL_IP));
932 test_unknown_type(mh, page, ARG_STR(SOL_IP), "IP_???");
933 }
934
935 static void
936 test_unknown_level(struct msghdr *const mh, void *const page)
937 {
938 struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0));
939
940 cmsg->cmsg_len = CMSG_LEN(0);
941 cmsg->cmsg_level = SOL_TCP;
942 cmsg->cmsg_type = 0xdeadbeef;
943
944 mh->msg_control = cmsg;
945 mh->msg_controllen = cmsg->cmsg_len;
946
947 int rc = sendmsg(-1, mh, 0);
948 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
949 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=%s"
950 ", cmsg_type=%#x}], msg_controllen=%u, msg_flags=0}"
951 ", 0) = %d %s (%m)\n",
952 (unsigned) cmsg->cmsg_len, "SOL_TCP", cmsg->cmsg_type,
953 (unsigned) mh->msg_controllen, rc, errno2name());
954 }
955
956 static void
957 test_big_len(struct msghdr *const mh)
958 {
959 int optmem_max;
960
961 if (read_int_from_file("/proc/sys/net/core/optmem_max", &optmem_max)
962 || optmem_max <= 0 || optmem_max > 0x100000)
963 optmem_max = sizeof(long long) * (2 * IOV_MAX + 512);
964 optmem_max = (optmem_max + sizeof(long long) - 1)
965 & ~(sizeof(long long) - 1);
966
967 const size_t len = optmem_max * 2;
968 struct cmsghdr *const cmsg = tail_alloc(len);
969 cmsg->cmsg_len = len;
970 cmsg->cmsg_level = SOL_SOCKET;
971 cmsg->cmsg_type = SCM_RIGHTS;
972
973 mh->msg_control = cmsg;
974 mh->msg_controllen = len;
975
976 int rc = sendmsg(-1, mh, 0);
977 if (EBADF != errno)
978 perror_msg_and_skip("sendmsg");
979
980 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
981 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
982 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
983 (unsigned) cmsg->cmsg_len);
984 print_fds(cmsg, optmem_max);
985 printf("}, ...], msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
986 (unsigned long) len, rc, errno2name());
987 }
988
989 int main(int ac, const char **av)
990 {
991 int rc = sendmsg(-1, 0, 0);
992 printf("sendmsg(-1, NULL, 0) = %d %s (%m)\n", rc, errno2name());
993
994 TAIL_ALLOC_OBJECT_CONST_PTR(struct msghdr, mh);
995 memset(mh, 0, sizeof(*mh));
996 test_big_len(mh);
997
998 rc = sendmsg(-1, mh + 1, 0);
999 printf("sendmsg(-1, %p, 0) = %d %s (%m)\n",
1000 mh + 1, rc, errno2name());
1001
1002 void *page = tail_alloc(1024) + 1024;
1003 mh->msg_control = page;
1004 mh->msg_controllen = CMSG_LEN(0);
1005 rc = sendmsg(-1, mh, 0);
1006 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
1007 ", msg_iovlen=0, msg_control=%p, msg_controllen=%u"
1008 ", msg_flags=0}, 0) = %d %s (%m)\n",
1009 page, (unsigned) CMSG_LEN(0), rc, errno2name());
1010
1011 test_sol_socket(mh, page);
1012 test_sol_ip(mh, page);
1013 test_unknown_level(mh, page);
1014
1015 puts("+++ exited with 0 +++");
1016 return 0;
1017 }