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