cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ioam6_parser.c (14782B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Author: Justin Iurman (justin.iurman@uliege.be)
      4 *
      5 * IOAM tester for IPv6, see ioam6.sh for details on each test case.
      6 */
      7#include <arpa/inet.h>
      8#include <errno.h>
      9#include <limits.h>
     10#include <linux/const.h>
     11#include <linux/if_ether.h>
     12#include <linux/ioam6.h>
     13#include <linux/ipv6.h>
     14#include <stdlib.h>
     15#include <string.h>
     16#include <unistd.h>
     17
     18struct ioam_config {
     19	__u32 id;
     20	__u64 wide;
     21	__u16 ingr_id;
     22	__u16 egr_id;
     23	__u32 ingr_wide;
     24	__u32 egr_wide;
     25	__u32 ns_data;
     26	__u64 ns_wide;
     27	__u32 sc_id;
     28	__u8 hlim;
     29	char *sc_data;
     30};
     31
     32/*
     33 * Be careful if you modify structs below - everything MUST be kept synchronized
     34 * with configurations inside ioam6.sh and always reflect the same.
     35 */
     36
     37static struct ioam_config node1 = {
     38	.id = 1,
     39	.wide = 11111111,
     40	.ingr_id = 0xffff, /* default value */
     41	.egr_id = 101,
     42	.ingr_wide = 0xffffffff, /* default value */
     43	.egr_wide = 101101,
     44	.ns_data = 0xdeadbee0,
     45	.ns_wide = 0xcafec0caf00dc0de,
     46	.sc_id = 777,
     47	.sc_data = "something that will be 4n-aligned",
     48	.hlim = 64,
     49};
     50
     51static struct ioam_config node2 = {
     52	.id = 2,
     53	.wide = 22222222,
     54	.ingr_id = 201,
     55	.egr_id = 202,
     56	.ingr_wide = 201201,
     57	.egr_wide = 202202,
     58	.ns_data = 0xdeadbee1,
     59	.ns_wide = 0xcafec0caf11dc0de,
     60	.sc_id = 666,
     61	.sc_data = "Hello there -Obi",
     62	.hlim = 63,
     63};
     64
     65static struct ioam_config node3 = {
     66	.id = 3,
     67	.wide = 33333333,
     68	.ingr_id = 301,
     69	.egr_id = 0xffff, /* default value */
     70	.ingr_wide = 301301,
     71	.egr_wide = 0xffffffff, /* default value */
     72	.ns_data = 0xdeadbee2,
     73	.ns_wide = 0xcafec0caf22dc0de,
     74	.sc_id = 0xffffff, /* default value */
     75	.sc_data = NULL,
     76	.hlim = 62,
     77};
     78
     79enum {
     80	/**********
     81	 * OUTPUT *
     82	 **********/
     83	TEST_OUT_UNDEF_NS,
     84	TEST_OUT_NO_ROOM,
     85	TEST_OUT_BIT0,
     86	TEST_OUT_BIT1,
     87	TEST_OUT_BIT2,
     88	TEST_OUT_BIT3,
     89	TEST_OUT_BIT4,
     90	TEST_OUT_BIT5,
     91	TEST_OUT_BIT6,
     92	TEST_OUT_BIT7,
     93	TEST_OUT_BIT8,
     94	TEST_OUT_BIT9,
     95	TEST_OUT_BIT10,
     96	TEST_OUT_BIT11,
     97	TEST_OUT_BIT22,
     98	TEST_OUT_FULL_SUPP_TRACE,
     99
    100	/*********
    101	 * INPUT *
    102	 *********/
    103	TEST_IN_UNDEF_NS,
    104	TEST_IN_NO_ROOM,
    105	TEST_IN_OFLAG,
    106	TEST_IN_BIT0,
    107	TEST_IN_BIT1,
    108	TEST_IN_BIT2,
    109	TEST_IN_BIT3,
    110	TEST_IN_BIT4,
    111	TEST_IN_BIT5,
    112	TEST_IN_BIT6,
    113	TEST_IN_BIT7,
    114	TEST_IN_BIT8,
    115	TEST_IN_BIT9,
    116	TEST_IN_BIT10,
    117	TEST_IN_BIT11,
    118	TEST_IN_BIT22,
    119	TEST_IN_FULL_SUPP_TRACE,
    120
    121	/**********
    122	 * GLOBAL *
    123	 **********/
    124	TEST_FWD_FULL_SUPP_TRACE,
    125
    126	__TEST_MAX,
    127};
    128
    129static int check_ioam_header(int tid, struct ioam6_trace_hdr *ioam6h,
    130			     __u32 trace_type, __u16 ioam_ns)
    131{
    132	if (__be16_to_cpu(ioam6h->namespace_id) != ioam_ns ||
    133	    __be32_to_cpu(ioam6h->type_be32) != (trace_type << 8))
    134		return 1;
    135
    136	switch (tid) {
    137	case TEST_OUT_UNDEF_NS:
    138	case TEST_IN_UNDEF_NS:
    139		return ioam6h->overflow ||
    140		       ioam6h->nodelen != 1 ||
    141		       ioam6h->remlen != 1;
    142
    143	case TEST_OUT_NO_ROOM:
    144	case TEST_IN_NO_ROOM:
    145	case TEST_IN_OFLAG:
    146		return !ioam6h->overflow ||
    147		       ioam6h->nodelen != 2 ||
    148		       ioam6h->remlen != 1;
    149
    150	case TEST_OUT_BIT0:
    151	case TEST_IN_BIT0:
    152	case TEST_OUT_BIT1:
    153	case TEST_IN_BIT1:
    154	case TEST_OUT_BIT2:
    155	case TEST_IN_BIT2:
    156	case TEST_OUT_BIT3:
    157	case TEST_IN_BIT3:
    158	case TEST_OUT_BIT4:
    159	case TEST_IN_BIT4:
    160	case TEST_OUT_BIT5:
    161	case TEST_IN_BIT5:
    162	case TEST_OUT_BIT6:
    163	case TEST_IN_BIT6:
    164	case TEST_OUT_BIT7:
    165	case TEST_IN_BIT7:
    166	case TEST_OUT_BIT11:
    167	case TEST_IN_BIT11:
    168		return ioam6h->overflow ||
    169		       ioam6h->nodelen != 1 ||
    170		       ioam6h->remlen;
    171
    172	case TEST_OUT_BIT8:
    173	case TEST_IN_BIT8:
    174	case TEST_OUT_BIT9:
    175	case TEST_IN_BIT9:
    176	case TEST_OUT_BIT10:
    177	case TEST_IN_BIT10:
    178		return ioam6h->overflow ||
    179		       ioam6h->nodelen != 2 ||
    180		       ioam6h->remlen;
    181
    182	case TEST_OUT_BIT22:
    183	case TEST_IN_BIT22:
    184		return ioam6h->overflow ||
    185		       ioam6h->nodelen ||
    186		       ioam6h->remlen;
    187
    188	case TEST_OUT_FULL_SUPP_TRACE:
    189	case TEST_IN_FULL_SUPP_TRACE:
    190	case TEST_FWD_FULL_SUPP_TRACE:
    191		return ioam6h->overflow ||
    192		       ioam6h->nodelen != 15 ||
    193		       ioam6h->remlen;
    194
    195	default:
    196		break;
    197	}
    198
    199	return 1;
    200}
    201
    202static int check_ioam6_data(__u8 **p, struct ioam6_trace_hdr *ioam6h,
    203			    const struct ioam_config cnf)
    204{
    205	unsigned int len;
    206	__u8 aligned;
    207	__u64 raw64;
    208	__u32 raw32;
    209
    210	if (ioam6h->type.bit0) {
    211		raw32 = __be32_to_cpu(*((__u32 *)*p));
    212		if (cnf.hlim != (raw32 >> 24) || cnf.id != (raw32 & 0xffffff))
    213			return 1;
    214		*p += sizeof(__u32);
    215	}
    216
    217	if (ioam6h->type.bit1) {
    218		raw32 = __be32_to_cpu(*((__u32 *)*p));
    219		if (cnf.ingr_id != (raw32 >> 16) ||
    220		    cnf.egr_id != (raw32 & 0xffff))
    221			return 1;
    222		*p += sizeof(__u32);
    223	}
    224
    225	if (ioam6h->type.bit2)
    226		*p += sizeof(__u32);
    227
    228	if (ioam6h->type.bit3)
    229		*p += sizeof(__u32);
    230
    231	if (ioam6h->type.bit4) {
    232		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
    233			return 1;
    234		*p += sizeof(__u32);
    235	}
    236
    237	if (ioam6h->type.bit5) {
    238		if (__be32_to_cpu(*((__u32 *)*p)) != cnf.ns_data)
    239			return 1;
    240		*p += sizeof(__u32);
    241	}
    242
    243	if (ioam6h->type.bit6)
    244		*p += sizeof(__u32);
    245
    246	if (ioam6h->type.bit7) {
    247		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
    248			return 1;
    249		*p += sizeof(__u32);
    250	}
    251
    252	if (ioam6h->type.bit8) {
    253		raw64 = __be64_to_cpu(*((__u64 *)*p));
    254		if (cnf.hlim != (raw64 >> 56) ||
    255		    cnf.wide != (raw64 & 0xffffffffffffff))
    256			return 1;
    257		*p += sizeof(__u64);
    258	}
    259
    260	if (ioam6h->type.bit9) {
    261		if (__be32_to_cpu(*((__u32 *)*p)) != cnf.ingr_wide)
    262			return 1;
    263		*p += sizeof(__u32);
    264
    265		if (__be32_to_cpu(*((__u32 *)*p)) != cnf.egr_wide)
    266			return 1;
    267		*p += sizeof(__u32);
    268	}
    269
    270	if (ioam6h->type.bit10) {
    271		if (__be64_to_cpu(*((__u64 *)*p)) != cnf.ns_wide)
    272			return 1;
    273		*p += sizeof(__u64);
    274	}
    275
    276	if (ioam6h->type.bit11) {
    277		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
    278			return 1;
    279		*p += sizeof(__u32);
    280	}
    281
    282	if (ioam6h->type.bit12) {
    283		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
    284			return 1;
    285		*p += sizeof(__u32);
    286	}
    287
    288	if (ioam6h->type.bit13) {
    289		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
    290			return 1;
    291		*p += sizeof(__u32);
    292	}
    293
    294	if (ioam6h->type.bit14) {
    295		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
    296			return 1;
    297		*p += sizeof(__u32);
    298	}
    299
    300	if (ioam6h->type.bit15) {
    301		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
    302			return 1;
    303		*p += sizeof(__u32);
    304	}
    305
    306	if (ioam6h->type.bit16) {
    307		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
    308			return 1;
    309		*p += sizeof(__u32);
    310	}
    311
    312	if (ioam6h->type.bit17) {
    313		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
    314			return 1;
    315		*p += sizeof(__u32);
    316	}
    317
    318	if (ioam6h->type.bit18) {
    319		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
    320			return 1;
    321		*p += sizeof(__u32);
    322	}
    323
    324	if (ioam6h->type.bit19) {
    325		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
    326			return 1;
    327		*p += sizeof(__u32);
    328	}
    329
    330	if (ioam6h->type.bit20) {
    331		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
    332			return 1;
    333		*p += sizeof(__u32);
    334	}
    335
    336	if (ioam6h->type.bit21) {
    337		if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
    338			return 1;
    339		*p += sizeof(__u32);
    340	}
    341
    342	if (ioam6h->type.bit22) {
    343		len = cnf.sc_data ? strlen(cnf.sc_data) : 0;
    344		aligned = cnf.sc_data ? __ALIGN_KERNEL(len, 4) : 0;
    345
    346		raw32 = __be32_to_cpu(*((__u32 *)*p));
    347		if (aligned != (raw32 >> 24) * 4 ||
    348		    cnf.sc_id != (raw32 & 0xffffff))
    349			return 1;
    350		*p += sizeof(__u32);
    351
    352		if (cnf.sc_data) {
    353			if (strncmp((char *)*p, cnf.sc_data, len))
    354				return 1;
    355
    356			*p += len;
    357			aligned -= len;
    358
    359			while (aligned--) {
    360				if (**p != '\0')
    361					return 1;
    362				*p += sizeof(__u8);
    363			}
    364		}
    365	}
    366
    367	return 0;
    368}
    369
    370static int check_ioam_header_and_data(int tid, struct ioam6_trace_hdr *ioam6h,
    371				      __u32 trace_type, __u16 ioam_ns)
    372{
    373	__u8 *p;
    374
    375	if (check_ioam_header(tid, ioam6h, trace_type, ioam_ns))
    376		return 1;
    377
    378	p = ioam6h->data + ioam6h->remlen * 4;
    379
    380	switch (tid) {
    381	case TEST_OUT_BIT0:
    382	case TEST_OUT_BIT1:
    383	case TEST_OUT_BIT2:
    384	case TEST_OUT_BIT3:
    385	case TEST_OUT_BIT4:
    386	case TEST_OUT_BIT5:
    387	case TEST_OUT_BIT6:
    388	case TEST_OUT_BIT7:
    389	case TEST_OUT_BIT8:
    390	case TEST_OUT_BIT9:
    391	case TEST_OUT_BIT10:
    392	case TEST_OUT_BIT11:
    393	case TEST_OUT_BIT22:
    394	case TEST_OUT_FULL_SUPP_TRACE:
    395		return check_ioam6_data(&p, ioam6h, node1);
    396
    397	case TEST_IN_BIT0:
    398	case TEST_IN_BIT1:
    399	case TEST_IN_BIT2:
    400	case TEST_IN_BIT3:
    401	case TEST_IN_BIT4:
    402	case TEST_IN_BIT5:
    403	case TEST_IN_BIT6:
    404	case TEST_IN_BIT7:
    405	case TEST_IN_BIT8:
    406	case TEST_IN_BIT9:
    407	case TEST_IN_BIT10:
    408	case TEST_IN_BIT11:
    409	case TEST_IN_BIT22:
    410	case TEST_IN_FULL_SUPP_TRACE:
    411	{
    412		__u32 tmp32 = node2.egr_wide;
    413		__u16 tmp16 = node2.egr_id;
    414		int res;
    415
    416		node2.egr_id = 0xffff;
    417		node2.egr_wide = 0xffffffff;
    418
    419		res = check_ioam6_data(&p, ioam6h, node2);
    420
    421		node2.egr_id = tmp16;
    422		node2.egr_wide = tmp32;
    423
    424		return res;
    425	}
    426
    427	case TEST_FWD_FULL_SUPP_TRACE:
    428		if (check_ioam6_data(&p, ioam6h, node3))
    429			return 1;
    430		if (check_ioam6_data(&p, ioam6h, node2))
    431			return 1;
    432		return check_ioam6_data(&p, ioam6h, node1);
    433
    434	default:
    435		break;
    436	}
    437
    438	return 1;
    439}
    440
    441static int str2id(const char *tname)
    442{
    443	if (!strcmp("out_undef_ns", tname))
    444		return TEST_OUT_UNDEF_NS;
    445	if (!strcmp("out_no_room", tname))
    446		return TEST_OUT_NO_ROOM;
    447	if (!strcmp("out_bit0", tname))
    448		return TEST_OUT_BIT0;
    449	if (!strcmp("out_bit1", tname))
    450		return TEST_OUT_BIT1;
    451	if (!strcmp("out_bit2", tname))
    452		return TEST_OUT_BIT2;
    453	if (!strcmp("out_bit3", tname))
    454		return TEST_OUT_BIT3;
    455	if (!strcmp("out_bit4", tname))
    456		return TEST_OUT_BIT4;
    457	if (!strcmp("out_bit5", tname))
    458		return TEST_OUT_BIT5;
    459	if (!strcmp("out_bit6", tname))
    460		return TEST_OUT_BIT6;
    461	if (!strcmp("out_bit7", tname))
    462		return TEST_OUT_BIT7;
    463	if (!strcmp("out_bit8", tname))
    464		return TEST_OUT_BIT8;
    465	if (!strcmp("out_bit9", tname))
    466		return TEST_OUT_BIT9;
    467	if (!strcmp("out_bit10", tname))
    468		return TEST_OUT_BIT10;
    469	if (!strcmp("out_bit11", tname))
    470		return TEST_OUT_BIT11;
    471	if (!strcmp("out_bit22", tname))
    472		return TEST_OUT_BIT22;
    473	if (!strcmp("out_full_supp_trace", tname))
    474		return TEST_OUT_FULL_SUPP_TRACE;
    475	if (!strcmp("in_undef_ns", tname))
    476		return TEST_IN_UNDEF_NS;
    477	if (!strcmp("in_no_room", tname))
    478		return TEST_IN_NO_ROOM;
    479	if (!strcmp("in_oflag", tname))
    480		return TEST_IN_OFLAG;
    481	if (!strcmp("in_bit0", tname))
    482		return TEST_IN_BIT0;
    483	if (!strcmp("in_bit1", tname))
    484		return TEST_IN_BIT1;
    485	if (!strcmp("in_bit2", tname))
    486		return TEST_IN_BIT2;
    487	if (!strcmp("in_bit3", tname))
    488		return TEST_IN_BIT3;
    489	if (!strcmp("in_bit4", tname))
    490		return TEST_IN_BIT4;
    491	if (!strcmp("in_bit5", tname))
    492		return TEST_IN_BIT5;
    493	if (!strcmp("in_bit6", tname))
    494		return TEST_IN_BIT6;
    495	if (!strcmp("in_bit7", tname))
    496		return TEST_IN_BIT7;
    497	if (!strcmp("in_bit8", tname))
    498		return TEST_IN_BIT8;
    499	if (!strcmp("in_bit9", tname))
    500		return TEST_IN_BIT9;
    501	if (!strcmp("in_bit10", tname))
    502		return TEST_IN_BIT10;
    503	if (!strcmp("in_bit11", tname))
    504		return TEST_IN_BIT11;
    505	if (!strcmp("in_bit22", tname))
    506		return TEST_IN_BIT22;
    507	if (!strcmp("in_full_supp_trace", tname))
    508		return TEST_IN_FULL_SUPP_TRACE;
    509	if (!strcmp("fwd_full_supp_trace", tname))
    510		return TEST_FWD_FULL_SUPP_TRACE;
    511
    512	return -1;
    513}
    514
    515static int ipv6_addr_equal(const struct in6_addr *a1, const struct in6_addr *a2)
    516{
    517	return ((a1->s6_addr32[0] ^ a2->s6_addr32[0]) |
    518		(a1->s6_addr32[1] ^ a2->s6_addr32[1]) |
    519		(a1->s6_addr32[2] ^ a2->s6_addr32[2]) |
    520		(a1->s6_addr32[3] ^ a2->s6_addr32[3])) == 0;
    521}
    522
    523static int get_u32(__u32 *val, const char *arg, int base)
    524{
    525	unsigned long res;
    526	char *ptr;
    527
    528	if (!arg || !*arg)
    529		return -1;
    530	res = strtoul(arg, &ptr, base);
    531
    532	if (!ptr || ptr == arg || *ptr)
    533		return -1;
    534
    535	if (res == ULONG_MAX && errno == ERANGE)
    536		return -1;
    537
    538	if (res > 0xFFFFFFFFUL)
    539		return -1;
    540
    541	*val = res;
    542	return 0;
    543}
    544
    545static int get_u16(__u16 *val, const char *arg, int base)
    546{
    547	unsigned long res;
    548	char *ptr;
    549
    550	if (!arg || !*arg)
    551		return -1;
    552	res = strtoul(arg, &ptr, base);
    553
    554	if (!ptr || ptr == arg || *ptr)
    555		return -1;
    556
    557	if (res == ULONG_MAX && errno == ERANGE)
    558		return -1;
    559
    560	if (res > 0xFFFFUL)
    561		return -1;
    562
    563	*val = res;
    564	return 0;
    565}
    566
    567static int (*func[__TEST_MAX])(int, struct ioam6_trace_hdr *, __u32, __u16) = {
    568	[TEST_OUT_UNDEF_NS]		= check_ioam_header,
    569	[TEST_OUT_NO_ROOM]		= check_ioam_header,
    570	[TEST_OUT_BIT0]		= check_ioam_header_and_data,
    571	[TEST_OUT_BIT1]		= check_ioam_header_and_data,
    572	[TEST_OUT_BIT2]		= check_ioam_header_and_data,
    573	[TEST_OUT_BIT3]		= check_ioam_header_and_data,
    574	[TEST_OUT_BIT4]		= check_ioam_header_and_data,
    575	[TEST_OUT_BIT5]		= check_ioam_header_and_data,
    576	[TEST_OUT_BIT6]		= check_ioam_header_and_data,
    577	[TEST_OUT_BIT7]		= check_ioam_header_and_data,
    578	[TEST_OUT_BIT8]		= check_ioam_header_and_data,
    579	[TEST_OUT_BIT9]		= check_ioam_header_and_data,
    580	[TEST_OUT_BIT10]		= check_ioam_header_and_data,
    581	[TEST_OUT_BIT11]		= check_ioam_header_and_data,
    582	[TEST_OUT_BIT22]		= check_ioam_header_and_data,
    583	[TEST_OUT_FULL_SUPP_TRACE]	= check_ioam_header_and_data,
    584	[TEST_IN_UNDEF_NS]		= check_ioam_header,
    585	[TEST_IN_NO_ROOM]		= check_ioam_header,
    586	[TEST_IN_OFLAG]		= check_ioam_header,
    587	[TEST_IN_BIT0]			= check_ioam_header_and_data,
    588	[TEST_IN_BIT1]			= check_ioam_header_and_data,
    589	[TEST_IN_BIT2]			= check_ioam_header_and_data,
    590	[TEST_IN_BIT3]			= check_ioam_header_and_data,
    591	[TEST_IN_BIT4]			= check_ioam_header_and_data,
    592	[TEST_IN_BIT5]			= check_ioam_header_and_data,
    593	[TEST_IN_BIT6]			= check_ioam_header_and_data,
    594	[TEST_IN_BIT7]			= check_ioam_header_and_data,
    595	[TEST_IN_BIT8]			= check_ioam_header_and_data,
    596	[TEST_IN_BIT9]			= check_ioam_header_and_data,
    597	[TEST_IN_BIT10]		= check_ioam_header_and_data,
    598	[TEST_IN_BIT11]		= check_ioam_header_and_data,
    599	[TEST_IN_BIT22]		= check_ioam_header_and_data,
    600	[TEST_IN_FULL_SUPP_TRACE]	= check_ioam_header_and_data,
    601	[TEST_FWD_FULL_SUPP_TRACE]	= check_ioam_header_and_data,
    602};
    603
    604int main(int argc, char **argv)
    605{
    606	int fd, size, hoplen, tid, ret = 1;
    607	struct in6_addr src, dst;
    608	struct ioam6_hdr *opt;
    609	struct ipv6hdr *ip6h;
    610	__u8 buffer[400], *p;
    611	__u16 ioam_ns;
    612	__u32 tr_type;
    613
    614	if (argc != 7)
    615		goto out;
    616
    617	tid = str2id(argv[2]);
    618	if (tid < 0 || !func[tid])
    619		goto out;
    620
    621	if (inet_pton(AF_INET6, argv[3], &src) != 1 ||
    622	    inet_pton(AF_INET6, argv[4], &dst) != 1)
    623		goto out;
    624
    625	if (get_u32(&tr_type, argv[5], 16) ||
    626	    get_u16(&ioam_ns, argv[6], 0))
    627		goto out;
    628
    629	fd = socket(AF_PACKET, SOCK_DGRAM, __cpu_to_be16(ETH_P_IPV6));
    630	if (!fd)
    631		goto out;
    632
    633	if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
    634		       argv[1], strlen(argv[1])))
    635		goto close;
    636
    637recv:
    638	size = recv(fd, buffer, sizeof(buffer), 0);
    639	if (size <= 0)
    640		goto close;
    641
    642	ip6h = (struct ipv6hdr *)buffer;
    643
    644	if (!ipv6_addr_equal(&ip6h->saddr, &src) ||
    645	    !ipv6_addr_equal(&ip6h->daddr, &dst))
    646		goto recv;
    647
    648	if (ip6h->nexthdr != IPPROTO_HOPOPTS)
    649		goto close;
    650
    651	p = buffer + sizeof(*ip6h);
    652	hoplen = (p[1] + 1) << 3;
    653	p += sizeof(struct ipv6_hopopt_hdr);
    654
    655	while (hoplen > 0) {
    656		opt = (struct ioam6_hdr *)p;
    657
    658		if (opt->opt_type == IPV6_TLV_IOAM &&
    659		    opt->type == IOAM6_TYPE_PREALLOC) {
    660			p += sizeof(*opt);
    661			ret = func[tid](tid, (struct ioam6_trace_hdr *)p,
    662					   tr_type, ioam_ns);
    663			break;
    664		}
    665
    666		p += opt->opt_len + 2;
    667		hoplen -= opt->opt_len + 2;
    668	}
    669close:
    670	close(fd);
    671out:
    672	return ret;
    673}