Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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*
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
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
};