1/*	$OpenBSD: print-vqp.c,v 1.8 2018/07/06 05:47:22 dlg Exp $	*/
2
3/*
4 * Copyright (c) 2006 Kevin Steves <stevesk@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19/*
20 * VLAN Query Protocol (VQP)
21 *
22 *    0                   1                   2                   3
23 *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
24 *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
25 *   |    Version    |    Opcode     | Response Code |  Data Count   |
26 *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
27 *   |                         Transaction ID                        |
28 *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
29 *   |                            Type (1)                           |
30 *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
31 *   |             Length            |            Data               /
32 *   /                                                               /
33 *   /                                                               /
34 *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35 *   |                            Type (n)                           |
36 *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37 *   |             Length            |            Data               /
38 *   /                                                               /
39 *   /                                                               /
40 *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41 *
42 * VQP is layered over UDP.  The default destination port is 1589.
43 *
44 */
45
46#include <sys/types.h>
47#include <sys/socket.h>
48
49#include <net/if.h>
50#include <netinet/in.h>
51#include <netinet/if_ether.h>
52#include <arpa/inet.h>
53
54#include <stdio.h>
55#include <string.h>
56
57#include "interface.h"
58#include "addrtoname.h"
59#include "extract.h"
60
61struct vqp_hdr {
62	u_char version;
63	u_char opcode;
64	u_char rcode;
65	u_char dcount;
66	u_int32_t xid;
67};
68
69#define VQP_JOIN			0x01
70#define VQP_JOIN_RESPONSE		0x02
71#define VQP_RECONFIRM			0x03
72#define VQP_RECONFIRM_RESPONSE		0x04
73
74#define VQP_NO_ERROR			0x00
75#define VQP_WRONG_VERSION		0x01
76#define VQP_INSUFFICIENT_RESOURCES	0x02
77#define VQP_DENY			0x03
78#define VQP_SHUTDOWN			0x04
79#define VQP_WRONG_MGMT_DOMAIN		0x05
80
81/* 4 bytes struct in_addr; IP address of VQP client */
82#define VQP_CLIENT_ADDR			0x00000c01
83/* string */
84#define VQP_PORT_NAME			0x00000c02
85/* string */
86#define VQP_VLAN_NAME			0x00000c03
87/* string; VTP domain if set */
88#define VQP_DOMAIN_NAME			0x00000c04
89/* ethernet frame */
90#define VQP_ETHERNET_FRAME		0x00000c05
91/* 6 bytes, mac address */
92#define VQP_MAC				0x00000c06
93/* 2 bytes? */
94#define VQP_UNKNOWN			0x00000c07
95/* 6 bytes, mac address */
96#define VQP_COOKIE			0x00000c08
97
98static void
99vqp_print_opcode(u_int val)
100{
101	switch (val) {
102	case VQP_JOIN:
103		printf("Join");
104		break;
105	case VQP_JOIN_RESPONSE:
106		printf("JoinResp");
107		break;
108	case VQP_RECONFIRM:
109		printf("Reconfirm");
110		break;
111	case VQP_RECONFIRM_RESPONSE:
112		printf("ReconfirmResp");
113		break;
114	default:
115		printf("unknown(%x)", val);
116		break;
117	}
118}
119
120static void
121vqp_print_rcode(u_int val)
122{
123	switch (val) {
124	case VQP_NO_ERROR:
125		printf("NoError");
126		break;
127	case VQP_WRONG_VERSION:
128		printf("WrongVersion");
129		break;
130	case VQP_INSUFFICIENT_RESOURCES:
131		printf("InsufficientResources");
132		break;
133	case VQP_DENY:
134		printf("Deny");
135		break;
136	case VQP_SHUTDOWN:
137		printf("Shutdown");
138		break;
139	case VQP_WRONG_MGMT_DOMAIN:
140		printf("WrongMgmtDomain");
141		break;
142	default:
143		printf("unknown(%x)", val);
144		break;
145	}
146}
147
148static void
149print_hex(const u_char *p, u_int len)
150{
151	while (len--)
152		printf("%02x", *p++);
153}
154
155static void
156vqp_print_type(u_int type, u_int len, const u_char *p)
157{
158	switch (type) {
159	case VQP_CLIENT_ADDR:
160		printf(" client:");
161		if (len == sizeof(struct in_addr)) {
162			struct in_addr in;
163			memcpy(&in, p, sizeof in);
164			printf("%s", inet_ntoa(in));
165		} else
166			print_hex(p, len);
167		break;
168	case VQP_PORT_NAME:
169		printf(" port:");
170		fn_printn(p, len, NULL);
171		break;
172	case VQP_VLAN_NAME:
173		printf(" vlan:");
174		fn_printn(p, len, NULL);
175		break;
176	case VQP_DOMAIN_NAME:
177		printf(" domain:");
178		fn_printn(p, len, NULL);
179		break;
180	case VQP_ETHERNET_FRAME:
181		printf(" ethernet:");
182		if (vflag > 1)
183			print_hex(p, len);
184		else if (len >= ETHER_ADDR_LEN * 2) {
185			p += ETHER_ADDR_LEN;	/* skip dst mac */
186			printf("%s", etheraddr_string(p)); /* src mac */
187		} else
188			print_hex(p, len);
189		break;
190	case VQP_MAC:
191		printf(" mac:");
192		if (len == ETHER_ADDR_LEN)
193			printf("%s", etheraddr_string(p));
194		else
195			print_hex(p, len);
196		break;
197	case VQP_UNKNOWN:
198		printf(" unknown:");
199		print_hex(p, len);
200		break;
201	case VQP_COOKIE:
202		printf(" cookie:");
203		if (len == ETHER_ADDR_LEN)
204			printf("%s", etheraddr_string(p));
205		else
206			print_hex(p, len);
207		break;
208	default:
209		printf(" unknown(%x/%u)", type, len);
210	}
211}
212
213void
214vqp_print(const u_char *bp, u_int len)
215{
216	struct vqp_hdr *p = (struct vqp_hdr *)bp;
217	u_int dcount;
218
219	TCHECK(p->version);
220	printf("VQPv%u", p->version);
221	if (p->version != 1)
222		return;
223	TCHECK(p->opcode);
224	printf("-");
225	vqp_print_opcode(p->opcode);
226	TCHECK(p->rcode);
227	printf(" rcode:");
228	vqp_print_rcode(p->rcode);
229	TCHECK(p->xid);
230	printf(" xid:0x%08x", ntohl(p->xid));
231	printf(" dcount:%u", p->dcount);
232	bp += sizeof(struct vqp_hdr);
233
234	dcount = p->dcount;
235	while (vflag && dcount > 0) {
236		u_int type, length;
237
238		TCHECK2(bp[0], 6);
239		type = EXTRACT_32BITS(bp);
240		bp += 4;
241		length = EXTRACT_16BITS(bp);
242		bp += 2;
243		TCHECK2(bp[0], length);
244		vqp_print_type(type, length, bp);
245		bp += length;
246		dcount--;
247	}
248
249	return;
250trunc:
251	printf("[|vqp]");
252}
253