1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include "dat.h"
5 #include "protos.h"
6
7 typedef struct Hdr Hdr;
8 struct Hdr
9 { uchar type;
10 uchar code;
11 uchar cksum[2]; /* Checksum */
12 uchar data[1];
13 };
14
15 enum
16 {
17 ICMP6LEN= 4,
18 };
19
20 enum
21 {
22 Ot, /* type */
23 Op, /* next protocol */
24 };
25
26 static Field p_fields[] =
27 {
28 {"t", Fnum, Ot, "type", } ,
29 {0}
30 };
31
32 enum
33 {
34 /* ICMPv6 types */
35 EchoReply = 0,
36 UnreachableV6 = 1,
37 PacketTooBigV6 = 2,
38 TimeExceedV6 = 3,
39 ParamProblemV6 = 4,
40 Redirect = 5,
41 EchoRequest = 8,
42 TimeExceed = 11,
43 InParmProblem = 12,
44 Timestamp = 13,
45 TimestampReply = 14,
46 InfoRequest = 15,
47 InfoReply = 16,
48 AddrMaskRequest = 17,
49 AddrMaskReply = 18,
50 EchoRequestV6 = 128,
51 EchoReplyV6 = 129,
52 RouterSolicit = 133,
53 RouterAdvert = 134,
54 NbrSolicit = 135,
55 NbrAdvert = 136,
56 RedirectV6 = 137,
57
58 Maxtype6 = 137,
59 };
60
61 static Mux p_mux[] =
62 {
63 {"ip6", UnreachableV6, },
64 {"ip6", RedirectV6, },
65 {"ip6", TimeExceedV6, },
66 {0},
67 };
68
69 char *icmpmsg6[256] =
70 {
71 [EchoReply] "EchoReply",
72 [UnreachableV6] "UnreachableV6",
73 [PacketTooBigV6] "PacketTooBigV6",
74 [TimeExceedV6] "TimeExceedV6",
75 [Redirect] "Redirect",
76 [EchoRequest] "EchoRequest",
77 [TimeExceed] "TimeExceed",
78 [InParmProblem] "InParmProblem",
79 [Timestamp] "Timestamp",
80 [TimestampReply] "TimestampReply",
81 [InfoRequest] "InfoRequest",
82 [InfoReply] "InfoReply",
83 [AddrMaskRequest] "AddrMaskRequest",
84 [AddrMaskReply] "AddrMaskReply",
85 [EchoRequestV6] "EchoRequestV6",
86 [EchoReplyV6] "EchoReplyV6",
87 [RouterSolicit] "RouterSolicit",
88 [RouterAdvert] "RouterAdvert",
89 [NbrSolicit] "NbrSolicit",
90 [NbrAdvert] "NbrAdvert",
91 [RedirectV6] "RedirectV6",
92 };
93
94 static char *unreachcode[] =
95 {
96 [0] "no route to destination",
97 [1] "comm with destination administratively prohibited",
98 [2] "icmp unreachable: unassigned error code (2)",
99 [3] "address unreachable",
100 [4] "port unreachable",
101 [5] "icmp unreachable: unknown code",
102 };
103
104 static char *timexcode[] =
105 {
106 [0] "hop limit exc",
107 [1] "reassmbl time exc",
108 [2] "icmp time exc: unknown code",
109 };
110
111 static char *parpcode[] =
112 {
113 [0] "erroneous header field encountered",
114 [1] "unrecognized Next Header type encountered",
115 [2] "unrecognized IPv6 option encountered",
116 [3] "icmp par prob: unknown code",
117 };
118 enum
119 {
120 sll = 1,
121 tll = 2,
122 pref = 3,
123 redir = 4,
124 mtu = 5,
125 };
126
127 static char *icmp6opts[256] =
128 {
129 [0] "unknown opt",
130 [1] "sll_addr",
131 [2] "tll_addr",
132 [3] "pref_opt",
133 [4] "redirect",
134 [5] "mtu_opt",
135 };
136
137 static void
p_compile(Filter * f)138 p_compile(Filter *f)
139 {
140 if(f->op == '='){
141 compile_cmp(icmp6.name, f, p_fields);
142 return;
143 }
144 if(strcmp(f->s, "ip6") == 0){
145 f->pr = p_mux->pr;
146 f->subop = Op;
147 return;
148 }
149 sysfatal("unknown icmp field or protocol: %s", f->s);
150 }
151
152 static int
p_filter(Filter * f,Msg * m)153 p_filter(Filter *f, Msg *m)
154 {
155 Hdr *h;
156
157 if(m->pe - m->ps < ICMP6LEN)
158 return 0;
159
160 h = (Hdr*)m->ps;
161 m->ps += ICMP6LEN;
162
163 switch(f->subop){
164
165 case Ot:
166 if(h->type == f->ulv)
167 return 1;
168 break;
169 case Op:
170 switch(h->type){
171 case UnreachableV6:
172 case RedirectV6:
173 case TimeExceedV6:
174 m->ps += 4;
175 return 1;
176 }
177 }
178 return 0;
179 }
180
181 static char*
opt_seprint(Msg * m)182 opt_seprint(Msg *m)
183 {
184 int otype, osz, pktsz;
185 uchar *a;
186 char *p = m->p;
187 char *e = m->e;
188 char *opt;
189 char optbuf[12];
190
191 pktsz = m->pe - m->ps;
192 a = m->ps;
193 while (pktsz > 0) {
194 otype = *a;
195 opt = icmp6opts[otype];
196 if(opt == nil){
197 sprint(optbuf, "0x%ux", otype);
198 opt = optbuf;
199 }
200 osz = (*(a+1)) * 8;
201
202 switch (otype) {
203 default:
204 p = seprint(p, e, "\n option=%s ", opt);
205 m->pr = &dump;
206 return p;
207
208 case sll:
209 case tll:
210 if (pktsz < osz || osz != 8) {
211 p = seprint(p, e, "\n option=%s bad size=%d",
212 opt, osz);
213 m->pr = &dump;
214 return p;
215 }
216 p = seprint(p, e, "\n option=%s maddr=%E", opt, a+2);
217 pktsz -= osz;
218 a += osz;
219 break;
220
221 case pref:
222 if ((pktsz < osz) || (osz != 32)) {
223 p = seprint(p, e, "\n option=%s: bad size=%d",
224 opt, osz);
225 m->pr = &dump;
226 return p;
227 }
228
229 p = seprint(p, e, "\n option=%s pref=%I "
230 "preflen=%3.3d lflag=%1.1d aflag=%1.1d "
231 "unused1=%1.1d validlt=%d preflt=%d unused2=%1.1d",
232 opt,
233 a+16,
234 (int) (*(a+2)),
235 (*(a+3) & (1 << 7)) != 0,
236 (*(a+3) & (1 << 6)) != 0,
237 (*(a+3) & 63) != 0,
238 NetL(a+4),
239 NetL(a+8),
240 NetL(a+12)!=0);
241
242 pktsz -= osz;
243 a += osz;
244 break;
245
246 case redir:
247 if (pktsz < osz) {
248 p = seprint(p, e, "\n option=%s: bad size=%d",
249 opt, osz);
250 m->pr = &dump;
251 return p;
252 }
253
254 p = seprint(p, e, "\n option=%s len %d", opt, osz);
255 a += osz;
256 m->ps = a;
257 return p;
258
259 case mtu:
260 if (pktsz < osz || osz != 8) {
261 p = seprint(p, e, "\n option=%s: bad size=%d",
262 opt, osz);
263 m->pr = &dump;
264 return p;
265 }
266
267 p = seprint(p, e, "\n option=%s unused=%1.1d mtu=%d",
268 opt, NetL(a+2) != 0, NetL(a+4));
269 pktsz -= osz;
270 a += osz;
271 break;
272 }
273 }
274
275 m->ps = a;
276 return p;
277 }
278
279 static int
p_seprint(Msg * m)280 p_seprint(Msg *m)
281 {
282 int i;
283 // ushort cksum2, cksum;
284 char *tn;
285 char *p = m->p;
286 char *e = m->e;
287 uchar *a;
288 Hdr *h;
289
290 h = (Hdr*)m->ps;
291 m->ps += ICMP6LEN;
292 m->pr = &dump;
293 a = m->ps;
294
295 if(m->pe - m->ps < ICMP6LEN)
296 return -1;
297
298 tn = icmpmsg6[h->type];
299 if(tn == nil)
300 p = seprint(p, e, "t=%ud c=%d ck=%4.4ux", h->type,
301 h->code, (ushort)NetS(h->cksum));
302 else
303 p = seprint(p, e, "t=%s c=%d ck=%4.4ux", tn,
304 h->code, (ushort)NetS(h->cksum));
305
306 /*
307 if(Cflag){
308 cksum = NetS(h->cksum);
309 h->cksum[0] = 0;
310 h->cksum[1] = 0;
311 cksum2 = ~ptclbsum((uchar*)h, m->pe - m->ps + ICMP6LEN) & 0xffff;
312 if(cksum != cksum2)
313 p = seprint(p,e, " !ck=%4.4ux", cksum2);
314 }
315 */
316
317 switch(h->type){
318
319 case UnreachableV6:
320 m->ps += 4;
321 m->pr = &ip6;
322 if (h->code >= nelem(unreachcode))
323 i = nelem(unreachcode)-1;
324 else
325 i = h->code;
326 p = seprint(p, e, " code=%s unused=%1.1d ", unreachcode[i],
327 NetL(a) != 0);
328 break;
329
330 case PacketTooBigV6:
331 m->ps += 4;
332 m->pr = &ip6;
333 p = seprint(p, e, " mtu=%4.4d ", NetL(a));
334 break;
335
336 case TimeExceedV6:
337 m->ps += 4;
338 m->pr = &ip6;
339 if (h->code >= nelem(timexcode))
340 i = nelem(timexcode)-1;
341 else
342 i = h->code;
343 p = seprint(p, e, " code=%s unused=%1.1d ", timexcode[i],
344 NetL(a) != 0);
345 break;
346
347 case ParamProblemV6:
348 m->ps += 4;
349 m->pr = &ip6;
350 if (h->code > nelem(parpcode))
351 i = nelem(parpcode)-1;
352 else
353 i = h->code;
354 p = seprint(p, e, " code=%s ptr=%2.2ux", parpcode[i], h->data[0]);
355 break;
356
357 case EchoReplyV6:
358 case EchoRequestV6:
359 m->ps += 4;
360 p = seprint(p, e, " id=%ux seq=%ux",
361 NetS(h->data), NetS(h->data+2));
362 break;
363
364 case RouterSolicit:
365 m->ps += 4;
366 m->pr = nil;
367 m->p = seprint(p, e, " unused=%1.1d ", NetL(a)!=0);
368 p = opt_seprint(m);
369 break;
370
371 case RouterAdvert:
372 m->ps += 12;
373 m->pr = nil;
374 m->p = seprint(p, e, " hoplim=%3.3d mflag=%1.1d oflag=%1.1d "
375 "unused=%1.1d routerlt=%8.8d reachtime=%d rxmtimer=%d",
376 (int) *a,
377 (*(a+1) & (1 << 7)) != 0,
378 (*(a+1) & (1 << 6)) != 0,
379 (*(a+1) & 63) != 0,
380 NetS(a+2),
381 NetL(a+4),
382 NetL(a+8));
383 p = opt_seprint(m);
384 break;
385
386 case NbrSolicit:
387 m->ps += 20;
388 m->pr = nil;
389 m->p = seprint(p, e, " unused=%1.1d targ %I", NetL(a) != 0, a+4);
390 p = opt_seprint(m);
391 break;
392
393 case NbrAdvert:
394 m->ps += 20;
395 m->pr = nil;
396 m->p = seprint(p, e, " rflag=%1.1d sflag=%1.1d oflag=%1.1d targ=%I",
397 (*a & (1 << 7)) != 0,
398 (*a & (1 << 6)) != 0,
399 (*a & (1 << 5)) != 0,
400 a+4);
401 p = opt_seprint(m);
402 break;
403
404 case RedirectV6:
405 m->ps += 36;
406 m->pr = &ip6;
407 m->p = seprint(p, e, " unused=%1.1d targ=%I dest=%I",
408 NetL(a) != 0, a+4, a+20);
409 p = opt_seprint(m);
410 break;
411
412 case Timestamp:
413 case TimestampReply:
414 m->ps += 12;
415 p = seprint(p, e, " orig=%ud rcv=%ux xmt=%ux",
416 NetL(h->data), NetL(h->data+4), NetL(h->data+8));
417 m->pr = nil;
418 break;
419
420 case InfoRequest:
421 case InfoReply:
422 break;
423
424 }
425 m->p = p;
426 return 0;
427 }
428
429 Proto icmp6 =
430 {
431 "icmp6",
432 p_compile,
433 p_filter,
434 p_seprint,
435 p_mux,
436 "%lud",
437 p_fields,
438 defaultframer,
439 };
440