plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

icmp6.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 bad size=%d", opt, osz);
    211 				m->pr = &dump;
    212 				return p;
    213 			}
    214 			p = seprint(p, e, "\n	  option=%s maddr=%E", opt, a+2);
    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: bad size=%d", opt, osz);
    222 				m->pr = &dump;
    223 				return p;
    224 			}
    225 
    226 			p = seprint(p, e, "\n	  option=%s pref=%I preflen=%3.3d lflag=%1.1d aflag=%1.1d unused1=%1.1d validlt=%d preflt=%d unused2=%1.1d",
    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: bad size=%d", opt, osz);
    244 				m->pr = &dump;
    245 				return p;
    246 			}
    247 
    248 			p = seprint(p, e, "\n	  option=%s len %d", opt, osz);
    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: bad size=%d", opt, osz);
    257 				m->pr = &dump;
    258 				return p;
    259 			}
    260 
    261 			p = seprint(p, e, "\n	  option=%s unused=%1.1d mtu=%d", opt, NetL(a+2)!=0, NetL(a+4));
    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) & 0xffff;
    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[i], NetL(a)!=0);
    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], NetL(a)!=0);
    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->data[0]);
    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.1d unused=%1.1d routerlt=%8.8d reachtime=%d rxmtimer=%d",
    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, a+4);
    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.1d targ=%I",
    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", NetL(a)!=0, a+4, a+20);
    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 };