aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/ip/snoopy/gre.c
blob: 2e744940815722b0f5149ae995d848063ea7eb98 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

/* GRE flag bits */
enum {
	GRE_chksum	= (1<<15),
	GRE_routing	= (1<<14),
	GRE_key		= (1<<13),
	GRE_seq		= (1<<12),
	GRE_srcrt	= (1<<11),
	GRE_recur	= (7<<8),
	GRE_ack		= (1<<7),
	GRE_ver		= 0x7
};

/* GRE protocols */
enum {
	GRE_sna		= 0x0004,
	GRE_osi		= 0x00fe,
	GRE_pup		= 0x0200,
	GRE_xns		= 0x0600,
	GRE_ip		= 0x0800,
	GRE_chaos	= 0x0804,
	GRE_rfc826	= 0x0806,
	GRE_frarp	= 0x0808,
	GRE_vines	= 0x0bad,
	GRE_vinesecho	= 0x0bae,
	GRE_vinesloop	= 0x0baf,
	GRE_decnetIV	= 0x6003,
	GRE_ppp		= 0x880b
};

int
sprintgre(void *a, char *buf, int len)
{
	int flag, prot, chksum, offset, key, seq, ack;
	int n;
	uchar *p = a;

	chksum = offset = key = seq = ack = 0;

	flag = NetS(p);
	prot = NetS(p+2);
	p += 4; len -= 4;
	if(flag & (GRE_chksum|GRE_routing)){
		chksum = NetS(p);
		offset = NetS(p+2);
		p += 4; len -= 4;
	}
	if(flag&GRE_key){
		key = NetL(p);
		p += 4; len -= 4;
	}
	if(flag&GRE_seq){
		seq = NetL(p);
		p += 4; len -= 4;
	}
	if(flag&GRE_ack){
		ack = NetL(p);
		p += 4; len -= 4;
	}
	/* skip routing if present */
	if(flag&GRE_routing) {
		while(len >= 4 && (n=p[3]) != 0) {
			len -= n;
			p += n;
		}
	}

	USED(offset);
	USED(chksum);

	n = sprint(buf, "GRE(f %4.4ux p %ux k %ux", flag, prot, key);
	if(flag&GRE_seq)
		n += sprint(buf+n, " s %ux", seq);
	if(flag&GRE_ack)
		n += sprint(buf+n, " a %ux", ack);
	n += sprint(buf+n, " len = %d/%d) ", len, key>>16);
	if(prot == GRE_ppp && len > 0)
		n += sprintppp(p, buf+n, len);
	else
		n += sprintx(p, buf+n, len);

	return n;
}