1 #include <netinet/in.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <stdint.h>
6 
7 #define OPT_X	42
8 #define OPT_Y	43
9 #define OPT_Z	44
10 
11 static void *
encode_inet6_opt(socklen_t * elp)12 encode_inet6_opt (socklen_t *elp)
13 {
14   void *eb = NULL;
15   socklen_t el;
16   int cl;
17   void *db;
18   int offset;
19   uint8_t val1;
20   uint16_t val2;
21   uint32_t val4;
22   uint64_t val8;
23 
24   *elp = 0;
25 #define CHECK() \
26   if (cl == -1)						\
27     {							\
28       printf ("cl == -1 on line %d\n", __LINE__);	\
29       free (eb);					\
30       return NULL;					\
31     }
32 
33   /* Estimate the length */
34   cl = inet6_opt_init (NULL, 0);
35   CHECK ();
36   cl = inet6_opt_append (NULL, 0, cl, OPT_X, 12, 8, NULL);
37   CHECK ();
38   cl = inet6_opt_append (NULL, 0, cl, OPT_Y, 7, 4, NULL);
39   CHECK ();
40   cl = inet6_opt_append (NULL, 0, cl, OPT_Z, 7, 1, NULL);
41   CHECK ();
42   cl = inet6_opt_finish (NULL, 0, cl);
43   CHECK ();
44   el = cl;
45 
46   eb = malloc (el + 8);
47   if (eb == NULL)
48     {
49       puts ("malloc failed");
50       return NULL;
51     }
52   /* Canary.  */
53   memcpy (eb + el, "deadbeef", 8);
54 
55   cl = inet6_opt_init (eb, el);
56   CHECK ();
57 
58   cl = inet6_opt_append (eb, el, cl, OPT_X, 12, 8, &db);
59   CHECK ();
60   val4 = 0x12345678;
61   offset = inet6_opt_set_val (db, 0, &val4, sizeof  (val4));
62   val8 = 0x0102030405060708LL;
63   inet6_opt_set_val (db, offset, &val8, sizeof  (val8));
64 
65   cl = inet6_opt_append (eb, el, cl, OPT_Y, 7, 4, &db);
66   CHECK ();
67   val1 = 0x01;
68   offset = inet6_opt_set_val (db, 0, &val1, sizeof  (val1));
69   val2 = 0x1331;
70   offset = inet6_opt_set_val (db, offset, &val2, sizeof  (val2));
71   val4 = 0x01020304;
72   inet6_opt_set_val (db, offset, &val4, sizeof  (val4));
73 
74   cl = inet6_opt_append (eb, el, cl, OPT_Z, 7, 1, &db);
75   CHECK ();
76   inet6_opt_set_val (db, 0, (void *) "abcdefg", 7);
77 
78   cl = inet6_opt_finish (eb, el, cl);
79   CHECK ();
80 
81   if (memcmp (eb + el, "deadbeef", 8) != 0)
82     {
83       puts ("Canary corrupted");
84       free (eb);
85       return NULL;
86     }
87   *elp = el;
88   return eb;
89 }
90 
91 int
decode_inet6_opt(void * eb,socklen_t el)92 decode_inet6_opt (void *eb, socklen_t el)
93 {
94   int ret = 0;
95   int seq = 0;
96   int cl = 0;
97   int offset;
98   uint8_t type;
99   socklen_t len;
100   uint8_t val1;
101   uint16_t val2;
102   uint32_t val4;
103   uint64_t val8;
104   void *db;
105   char buf[8];
106 
107   while ((cl = inet6_opt_next (eb, el, cl, &type, &len, &db)) != -1)
108     switch (type)
109       {
110       case OPT_X:
111 	if (seq++ != 0)
112 	  {
113 	    puts ("OPT_X is not first");
114 	    ret = 1;
115 	  }
116 	if (len != 12)
117 	  {
118 	    printf ("OPT_X's length %d != 12\n", len);
119 	    ret = 1;
120 	  }
121 	offset = inet6_opt_get_val (db, 0, &val4, sizeof (val4));
122 	if (val4 != 0x12345678)
123 	  {
124 	    printf ("OPT_X's val4 %x != 0x12345678\n", val4);
125 	    ret = 1;
126 	  }
127 	offset = inet6_opt_get_val (db, offset, &val8, sizeof (val8));
128 	if (offset != len || val8 != 0x0102030405060708LL)
129 	  {
130 	    printf ("OPT_X's val8 %llx != 0x0102030405060708\n",
131 		    (long long) val8);
132 	    ret = 1;
133 	  }
134 	break;
135       case OPT_Y:
136 	if (seq++ != 1)
137 	  {
138 	    puts ("OPT_Y is not second");
139 	    ret = 1;
140 	  }
141 	if (len != 7)
142 	  {
143 	    printf ("OPT_Y's length %d != 7\n", len);
144 	    ret = 1;
145 	  }
146 	offset = inet6_opt_get_val (db, 0, &val1, sizeof (val1));
147 	if (val1 != 0x01)
148 	  {
149 	    printf ("OPT_Y's val1 %x != 0x01\n", val1);
150 	    ret = 1;
151 	  }
152 	offset = inet6_opt_get_val (db, offset, &val2, sizeof (val2));
153 	if (val2 != 0x1331)
154 	  {
155 	    printf ("OPT_Y's val2 %x != 0x1331\n", val2);
156 	    ret = 1;
157 	  }
158 	offset = inet6_opt_get_val (db, offset, &val4, sizeof (val4));
159 	if (offset != len || val4 != 0x01020304)
160 	  {
161 	    printf ("OPT_Y's val4 %x != 0x01020304\n", val4);
162 	    ret = 1;
163 	  }
164 	break;
165       case OPT_Z:
166 	if (seq++ != 2)
167 	  {
168 	    puts ("OPT_Z is not third");
169 	    ret = 1;
170 	  }
171 	if (len != 7)
172 	  {
173 	    printf ("OPT_Z's length %d != 7\n", len);
174 	    ret = 1;
175 	  }
176 	offset = inet6_opt_get_val (db, 0, buf, 7);
177 	if (offset != len || memcmp (buf, "abcdefg", 7) != 0)
178 	  {
179 	    buf[7] = '\0';
180 	    printf ("OPT_Z's buf \"%s\" != \"abcdefg\"\n", buf);
181 	    ret = 1;
182 	  }
183 	break;
184       default:
185 	printf ("Unknown option %d\n", type);
186 	ret = 1;
187 	break;
188       }
189   if (seq != 3)
190     {
191       puts ("Didn't see all of OPT_X, OPT_Y and OPT_Z");
192       ret = 1;
193     }
194   return ret;
195 }
196 
197 static int
do_test(void)198 do_test (void)
199 {
200   void *eb;
201   socklen_t el;
202   eb = encode_inet6_opt (&el);
203   if (eb == NULL)
204     return 1;
205   if (decode_inet6_opt (eb, el))
206     return 1;
207   return 0;
208 }
209 
210 #define TEST_FUNCTION do_test ()
211 #include "../test-skeleton.c"
212