117680Spst/*
217680Spst * Copyright (c) 1995, 1996
317680Spst *	The Regents of the University of California.  All rights reserved.
417680Spst *
517680Spst * Redistribution and use in source and binary forms, with or without
617680Spst * modification, are permitted provided that: (1) source code distributions
717680Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817680Spst * distributions including binary code include the above copyright notice and
917680Spst * this paragraph in its entirety in the documentation or other materials
1017680Spst * provided with the distribution, and (3) all advertising materials mentioning
1117680Spst * features or use of this software display the following acknowledgement:
1217680Spst * ``This product includes software developed by the University of California,
1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417680Spst * the University nor the names of its contributors may be used to endorse
1517680Spst * or promote products derived from this software without specific prior
1617680Spst * written permission.
1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2017680Spst */
2117680Spst
22313537Sglebius/* \summary: Distance Vector Multicast Routing Protocol printer */
23313537Sglebius
2456893Sfenner#ifdef HAVE_CONFIG_H
2556893Sfenner#include "config.h"
2656893Sfenner#endif
2756893Sfenner
28313537Sglebius#include <netdissect-stdinc.h>
2917680Spst
30313537Sglebius#include "netdissect.h"
3156893Sfenner#include "extract.h"
3217680Spst#include "addrtoname.h"
3317680Spst
3417680Spst/*
35356341Scy * See: RFC 1075 and draft-ietf-idmr-dvmrp-v3
36356341Scy *
3717680Spst * DVMRP message types and flag values shamelessly stolen from
3817680Spst * mrouted/dvmrp.h.
3917680Spst */
4017680Spst#define DVMRP_PROBE		1	/* for finding neighbors */
4117680Spst#define DVMRP_REPORT		2	/* for reporting some or all routes */
4217680Spst#define DVMRP_ASK_NEIGHBORS	3	/* sent by mapper, asking for a list */
4398524Sfenner					/* of this router's neighbors */
4417680Spst#define DVMRP_NEIGHBORS		4	/* response to such a request */
4517680Spst#define DVMRP_ASK_NEIGHBORS2	5	/* as above, want new format reply */
4617680Spst#define DVMRP_NEIGHBORS2	6
4717680Spst#define DVMRP_PRUNE		7	/* prune message */
4817680Spst#define DVMRP_GRAFT		8	/* graft message */
4917680Spst#define DVMRP_GRAFT_ACK		9	/* graft acknowledgement */
5017680Spst
5117680Spst/*
5217680Spst * 'flags' byte values in DVMRP_NEIGHBORS2 reply.
5317680Spst */
5417680Spst#define DVMRP_NF_TUNNEL		0x01	/* neighbors reached via tunnel */
5517680Spst#define DVMRP_NF_SRCRT		0x02	/* tunnel uses IP source routing */
5617680Spst#define DVMRP_NF_DOWN		0x10	/* kernel state of interface */
5717680Spst#define DVMRP_NF_DISABLED	0x20	/* administratively disabled */
5817680Spst#define DVMRP_NF_QUERIER	0x40	/* I am the subnet's querier */
5917680Spst
60276788Sdelphijstatic int print_probe(netdissect_options *, const u_char *, const u_char *, u_int);
61276788Sdelphijstatic int print_report(netdissect_options *, const u_char *, const u_char *, u_int);
62276788Sdelphijstatic int print_neighbors(netdissect_options *, const u_char *, const u_char *, u_int);
63356341Scystatic int print_neighbors2(netdissect_options *, const u_char *, const u_char *, u_int, uint8_t, uint8_t);
64276788Sdelphijstatic int print_prune(netdissect_options *, const u_char *);
65276788Sdelphijstatic int print_graft(netdissect_options *, const u_char *);
66276788Sdelphijstatic int print_graft_ack(netdissect_options *, const u_char *);
6717680Spst
6817680Spstvoid
69276788Sdelphijdvmrp_print(netdissect_options *ndo,
70276788Sdelphij            register const u_char *bp, register u_int len)
7117680Spst{
7217680Spst	register const u_char *ep;
7317680Spst	register u_char type;
74356341Scy	uint8_t major_version, minor_version;
7517680Spst
76276788Sdelphij	ep = (const u_char *)ndo->ndo_snapend;
7717680Spst	if (bp >= ep)
7817680Spst		return;
7917680Spst
80276788Sdelphij	ND_TCHECK(bp[1]);
8117680Spst	type = bp[1];
8298524Sfenner
8398524Sfenner	/* Skip IGMP header */
8417680Spst	bp += 8;
8517680Spst	len -= 8;
8617680Spst
8717680Spst	switch (type) {
8826180Sfenner
8917680Spst	case DVMRP_PROBE:
90276788Sdelphij		ND_PRINT((ndo, " Probe"));
91276788Sdelphij		if (ndo->ndo_vflag) {
92276788Sdelphij			if (print_probe(ndo, bp, ep, len) < 0)
93127668Sbms				goto trunc;
94127668Sbms		}
9517680Spst		break;
9617680Spst
9717680Spst	case DVMRP_REPORT:
98276788Sdelphij		ND_PRINT((ndo, " Report"));
99276788Sdelphij		if (ndo->ndo_vflag > 1) {
100276788Sdelphij			if (print_report(ndo, bp, ep, len) < 0)
101127668Sbms				goto trunc;
102127668Sbms		}
10317680Spst		break;
10417680Spst
10517680Spst	case DVMRP_ASK_NEIGHBORS:
106276788Sdelphij		ND_PRINT((ndo, " Ask-neighbors(old)"));
10717680Spst		break;
10817680Spst
10917680Spst	case DVMRP_NEIGHBORS:
110276788Sdelphij		ND_PRINT((ndo, " Neighbors(old)"));
111276788Sdelphij		if (print_neighbors(ndo, bp, ep, len) < 0)
112127668Sbms			goto trunc;
11317680Spst		break;
11417680Spst
11517680Spst	case DVMRP_ASK_NEIGHBORS2:
116276788Sdelphij		ND_PRINT((ndo, " Ask-neighbors2"));
11717680Spst		break;
11817680Spst
11917680Spst	case DVMRP_NEIGHBORS2:
120276788Sdelphij		ND_PRINT((ndo, " Neighbors2"));
12117680Spst		/*
122356341Scy		 * extract version from IGMP group address field
12317680Spst		 */
12426180Sfenner		bp -= 4;
125276788Sdelphij		ND_TCHECK2(bp[0], 4);
126356341Scy		major_version = *(bp + 3);
127356341Scy		minor_version = *(bp + 2);
12826180Sfenner		bp += 4;
129356341Scy		if (print_neighbors2(ndo, bp, ep, len, major_version,
130356341Scy		    minor_version) < 0)
131127668Sbms			goto trunc;
13217680Spst		break;
13317680Spst
13417680Spst	case DVMRP_PRUNE:
135276788Sdelphij		ND_PRINT((ndo, " Prune"));
136276788Sdelphij		if (print_prune(ndo, bp) < 0)
137127668Sbms			goto trunc;
13817680Spst		break;
13917680Spst
14017680Spst	case DVMRP_GRAFT:
141276788Sdelphij		ND_PRINT((ndo, " Graft"));
142276788Sdelphij		if (print_graft(ndo, bp) < 0)
143127668Sbms			goto trunc;
14417680Spst		break;
14517680Spst
14617680Spst	case DVMRP_GRAFT_ACK:
147276788Sdelphij		ND_PRINT((ndo, " Graft-ACK"));
148276788Sdelphij		if (print_graft_ack(ndo, bp) < 0)
149127668Sbms			goto trunc;
15017680Spst		break;
15117680Spst
15217680Spst	default:
153276788Sdelphij		ND_PRINT((ndo, " [type %d]", type));
15417680Spst		break;
15517680Spst	}
156127668Sbms	return;
157127668Sbms
158127668Sbmstrunc:
159276788Sdelphij	ND_PRINT((ndo, "[|dvmrp]"));
160127668Sbms	return;
16117680Spst}
16217680Spst
163276788Sdelphijstatic int
164276788Sdelphijprint_report(netdissect_options *ndo,
165276788Sdelphij             register const u_char *bp, register const u_char *ep,
166276788Sdelphij             register u_int len)
16717680Spst{
168276788Sdelphij	register uint32_t mask, origin;
169127668Sbms	register int metric, done;
170127668Sbms	register u_int i, width;
17117680Spst
17217680Spst	while (len > 0) {
17317680Spst		if (len < 3) {
174276788Sdelphij			ND_PRINT((ndo, " [|]"));
175127668Sbms			return (0);
17617680Spst		}
177276788Sdelphij		ND_TCHECK2(bp[0], 3);
178276788Sdelphij		mask = (uint32_t)0xff << 24 | bp[0] << 16 | bp[1] << 8 | bp[2];
17917680Spst		width = 1;
18017680Spst		if (bp[0])
18117680Spst			width = 2;
18217680Spst		if (bp[1])
18317680Spst			width = 3;
18417680Spst		if (bp[2])
18517680Spst			width = 4;
18617680Spst
187276788Sdelphij		ND_PRINT((ndo, "\n\tMask %s", intoa(htonl(mask))));
18817680Spst		bp += 3;
18917680Spst		len -= 3;
19017680Spst		do {
19117680Spst			if (bp + width + 1 > ep) {
192276788Sdelphij				ND_PRINT((ndo, " [|]"));
193127668Sbms				return (0);
19417680Spst			}
19517680Spst			if (len < width + 1) {
196276788Sdelphij				ND_PRINT((ndo, "\n\t  [Truncated Report]"));
197127668Sbms				return (0);
19817680Spst			}
19917680Spst			origin = 0;
200127668Sbms			for (i = 0; i < width; ++i) {
201276788Sdelphij				ND_TCHECK(*bp);
20217680Spst				origin = origin << 8 | *bp++;
203127668Sbms			}
20417680Spst			for ( ; i < 4; ++i)
20517680Spst				origin <<= 8;
20617680Spst
207276788Sdelphij			ND_TCHECK(*bp);
20817680Spst			metric = *bp++;
20917680Spst			done = metric & 0x80;
21017680Spst			metric &= 0x7f;
211276788Sdelphij			ND_PRINT((ndo, "\n\t  %s metric %d", intoa(htonl(origin)),
212276788Sdelphij				metric));
21317680Spst			len -= width + 1;
21417680Spst		} while (!done);
21517680Spst	}
216127668Sbms	return (0);
217127668Sbmstrunc:
218127668Sbms	return (-1);
21917680Spst}
22017680Spst
221127668Sbmsstatic int
222276788Sdelphijprint_probe(netdissect_options *ndo,
223276788Sdelphij            register const u_char *bp, register const u_char *ep,
224276788Sdelphij            register u_int len)
22517680Spst{
226276788Sdelphij	register uint32_t genid;
22726180Sfenner
228276788Sdelphij	ND_TCHECK2(bp[0], 4);
22926180Sfenner	if ((len < 4) || ((bp + 4) > ep)) {
23026180Sfenner		/* { (ctags) */
231276788Sdelphij		ND_PRINT((ndo, " [|}"));
232127668Sbms		return (0);
23326180Sfenner	}
234356341Scy	genid = EXTRACT_32BITS(bp);
23526180Sfenner	bp += 4;
23626180Sfenner	len -= 4;
237276788Sdelphij	ND_PRINT((ndo, ndo->ndo_vflag > 1 ? "\n\t" : " "));
238276788Sdelphij	ND_PRINT((ndo, "genid %u", genid));
239276788Sdelphij	if (ndo->ndo_vflag < 2)
240127668Sbms		return (0);
24126180Sfenner
24226180Sfenner	while ((len > 0) && (bp < ep)) {
243276788Sdelphij		ND_TCHECK2(bp[0], 4);
244276788Sdelphij		ND_PRINT((ndo, "\n\tneighbor %s", ipaddr_string(ndo, bp)));
24556893Sfenner		bp += 4; len -= 4;
24626180Sfenner	}
247127668Sbms	return (0);
24856893Sfennertrunc:
249127668Sbms	return (-1);
25026180Sfenner}
25126180Sfenner
252127668Sbmsstatic int
253276788Sdelphijprint_neighbors(netdissect_options *ndo,
254276788Sdelphij                register const u_char *bp, register const u_char *ep,
255276788Sdelphij                register u_int len)
25626180Sfenner{
25756893Sfenner	const u_char *laddr;
25826180Sfenner	register u_char metric;
25926180Sfenner	register u_char thresh;
26026180Sfenner	register int ncount;
26117680Spst
26217680Spst	while (len > 0 && bp < ep) {
263276788Sdelphij		ND_TCHECK2(bp[0], 7);
26456893Sfenner		laddr = bp;
26556893Sfenner		bp += 4;
26617680Spst		metric = *bp++;
26717680Spst		thresh = *bp++;
26817680Spst		ncount = *bp++;
26917680Spst		len -= 7;
27056893Sfenner		while (--ncount >= 0) {
271276788Sdelphij			ND_TCHECK2(bp[0], 4);
272276788Sdelphij			ND_PRINT((ndo, " [%s ->", ipaddr_string(ndo, laddr)));
273276788Sdelphij			ND_PRINT((ndo, " %s, (%d/%d)]",
274276788Sdelphij				   ipaddr_string(ndo, bp), metric, thresh));
27556893Sfenner			bp += 4;
27617680Spst			len -= 4;
27717680Spst		}
27817680Spst	}
279127668Sbms	return (0);
28056893Sfennertrunc:
281127668Sbms	return (-1);
28217680Spst}
28317680Spst
284127668Sbmsstatic int
285276788Sdelphijprint_neighbors2(netdissect_options *ndo,
286276788Sdelphij                 register const u_char *bp, register const u_char *ep,
287356341Scy                 register u_int len, uint8_t major_version,
288356341Scy                 uint8_t minor_version)
28917680Spst{
29056893Sfenner	const u_char *laddr;
29126180Sfenner	register u_char metric, thresh, flags;
29226180Sfenner	register int ncount;
29317680Spst
294356341Scy	ND_PRINT((ndo, " (v %d.%d):", major_version, minor_version));
29517680Spst
29617680Spst	while (len > 0 && bp < ep) {
297276788Sdelphij		ND_TCHECK2(bp[0], 8);
29856893Sfenner		laddr = bp;
29956893Sfenner		bp += 4;
30017680Spst		metric = *bp++;
30117680Spst		thresh = *bp++;
30217680Spst		flags = *bp++;
30317680Spst		ncount = *bp++;
30417680Spst		len -= 8;
30526180Sfenner		while (--ncount >= 0 && (len >= 4) && (bp + 4) <= ep) {
306276788Sdelphij			ND_PRINT((ndo, " [%s -> ", ipaddr_string(ndo, laddr)));
307276788Sdelphij			ND_PRINT((ndo, "%s (%d/%d", ipaddr_string(ndo, bp),
308276788Sdelphij				     metric, thresh));
30917680Spst			if (flags & DVMRP_NF_TUNNEL)
310276788Sdelphij				ND_PRINT((ndo, "/tunnel"));
31117680Spst			if (flags & DVMRP_NF_SRCRT)
312276788Sdelphij				ND_PRINT((ndo, "/srcrt"));
31317680Spst			if (flags & DVMRP_NF_QUERIER)
314276788Sdelphij				ND_PRINT((ndo, "/querier"));
31517680Spst			if (flags & DVMRP_NF_DISABLED)
316276788Sdelphij				ND_PRINT((ndo, "/disabled"));
31717680Spst			if (flags & DVMRP_NF_DOWN)
318276788Sdelphij				ND_PRINT((ndo, "/down"));
319276788Sdelphij			ND_PRINT((ndo, ")]"));
32056893Sfenner			bp += 4;
32117680Spst			len -= 4;
32217680Spst		}
32317680Spst		if (ncount != -1) {
324276788Sdelphij			ND_PRINT((ndo, " [|]"));
325127668Sbms			return (0);
32617680Spst		}
32717680Spst	}
328127668Sbms	return (0);
32956893Sfennertrunc:
330127668Sbms	return (-1);
33117680Spst}
33217680Spst
333127668Sbmsstatic int
334276788Sdelphijprint_prune(netdissect_options *ndo,
335276788Sdelphij            register const u_char *bp)
33617680Spst{
337276788Sdelphij	ND_TCHECK2(bp[0], 12);
338276788Sdelphij	ND_PRINT((ndo, " src %s grp %s", ipaddr_string(ndo, bp), ipaddr_string(ndo, bp + 4)));
33917680Spst	bp += 8;
340276788Sdelphij	ND_PRINT((ndo, " timer "));
341313537Sglebius	unsigned_relts_print(ndo, EXTRACT_32BITS(bp));
342127668Sbms	return (0);
34356893Sfennertrunc:
344127668Sbms	return (-1);
34517680Spst}
34617680Spst
347127668Sbmsstatic int
348276788Sdelphijprint_graft(netdissect_options *ndo,
349276788Sdelphij            register const u_char *bp)
35017680Spst{
351276788Sdelphij	ND_TCHECK2(bp[0], 8);
352276788Sdelphij	ND_PRINT((ndo, " src %s grp %s", ipaddr_string(ndo, bp), ipaddr_string(ndo, bp + 4)));
353127668Sbms	return (0);
35456893Sfennertrunc:
355127668Sbms	return (-1);
35617680Spst}
35717680Spst
358127668Sbmsstatic int
359276788Sdelphijprint_graft_ack(netdissect_options *ndo,
360276788Sdelphij                register const u_char *bp)
36117680Spst{
362276788Sdelphij	ND_TCHECK2(bp[0], 8);
363276788Sdelphij	ND_PRINT((ndo, " src %s grp %s", ipaddr_string(ndo, bp), ipaddr_string(ndo, bp + 4)));
364127668Sbms	return (0);
36556893Sfennertrunc:
366127668Sbms	return (-1);
36717680Spst}
368