xref: /openbsd-src/usr.sbin/tcpdump/print-slow.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /* 	$OpenBSD: print-slow.c,v 1.1 2008/10/16 12:57:01 mpf Exp $ 	*/
2 
3 /*
4  * Copyright (c) 1998-2005 The TCPDUMP project
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that: (1) source code
8  * distributions retain the above copyright notice and this paragraph
9  * in its entirety, and (2) distributions including binary code include
10  * the above copyright notice and this paragraph in its entirety in
11  * the documentation or other materials provided with the distribution.
12  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
13  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
14  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
15  * FOR A PARTICULAR PURPOSE.
16  *
17  * support for the IEEE "slow protocols" LACP, MARKER as per 802.3ad
18  *
19  * Original code by Hannes Gredler (hannes@juniper.net)
20  */
21 
22 #include <sys/param.h>
23 #include <sys/time.h>
24 #include <sys/socket.h>
25 #include <sys/file.h>
26 #include <sys/ioctl.h>
27 
28 #include <net/if.h>
29 
30 #include <netinet/in.h>
31 #include <netinet/in_systm.h>
32 #include <netinet/ip.h>
33 #include <netinet/if_ether.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 #include "interface.h"
39 #include "extract.h"
40 #include "addrtoname.h"
41 
42 
43 struct slow_common_header {
44 	u_int8_t proto_subtype;
45 	u_int8_t version;
46 };
47 
48 #define	SLOW_PROTO_LACP                     1
49 #define	SLOW_PROTO_MARKER                   2
50 
51 #define	LACP_VERSION                        1
52 #define	MARKER_VERSION                      1
53 
54 static const struct tok slow_proto_values[] = {
55 	{ SLOW_PROTO_LACP, "LACP" },
56 	{ SLOW_PROTO_MARKER, "MARKER" },
57 	{ 0, NULL}
58 };
59 
60 struct tlv_header_t {
61 	u_int8_t type;
62 	u_int8_t length;
63 };
64 
65 #define LACP_TLV_TERMINATOR     0x00
66 #define LACP_TLV_ACTOR_INFO     0x01
67 #define LACP_TLV_PARTNER_INFO   0x02
68 #define LACP_TLV_COLLECTOR_INFO 0x03
69 
70 #define MARKER_TLV_TERMINATOR   0x00
71 #define MARKER_TLV_MARKER_INFO  0x01
72 #define MARKER_TLV_MARKER_RESP  0x02
73 
74 static const struct tok slow_tlv_values[] = {
75 	{ (SLOW_PROTO_LACP << 8) + LACP_TLV_TERMINATOR, "Terminator"},
76 	{ (SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO, "Actor Information"},
77 	{ (SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO,
78 	    "Partner Information"},
79 	{ (SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO,
80 	    "Collector Information"},
81 
82 	{ (SLOW_PROTO_MARKER << 8) + MARKER_TLV_TERMINATOR, "Terminator"},
83 	{ (SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO,
84 	    "Marker Information"},
85 	{ (SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_RESP,
86 	    "Marker Response Information"},
87 	{ 0, NULL}
88 };
89 
90 struct lacp_tlv_actor_partner_info_t {
91 	u_int8_t sys_pri[2];
92 	u_int8_t sys[ETHER_ADDR_LEN];
93 	u_int8_t key[2];
94 	u_int8_t port_pri[2];
95 	u_int8_t port[2];
96 	u_int8_t state;
97 	u_int8_t pad[3];
98 };
99 
100 #define ACTOR_PARTNER_BITS \
101 "\020\1Activity\2Timeout\3Aggregation\4Synchronization\5Collecting\
102 \6Distributing\7Default\10Expired"
103 
104 struct lacp_tlv_collector_info_t {
105 	u_int8_t max_delay[2];
106 	u_int8_t pad[12];
107 };
108 
109 struct marker_tlv_marker_info_t {
110 	u_int8_t req_port[2];
111 	u_int8_t req_sys[ETHER_ADDR_LEN];
112 	u_int8_t req_trans_id[4];
113 	u_int8_t pad[2];
114 };
115 
116 struct lacp_marker_tlv_terminator_t {
117 	u_int8_t pad[50];
118 };
119 
120 void
121 slow_print(register const u_char *pptr, register u_int len)
122 {
123 
124 	const struct slow_common_header *slow_com_header;
125 	const struct tlv_header_t *tlv_header;
126 	const u_char *tptr, *tlv_tptr;
127 	u_int tlv_len, tlen, tlv_tlen;
128 
129 	union {
130 		struct lacp_marker_tlv_terminator_t *marker_terminator;
131 		struct lacp_tlv_actor_partner_info_t *actor_partner_info;
132 		struct lacp_tlv_collector_info_t *collector_info;
133 		struct marker_tlv_marker_info_t *marker_tlv_marker_info;
134 	} tlv_ptr;
135 
136 	tptr = pptr;
137 	slow_com_header = (const struct slow_common_header *)pptr;
138 	TCHECK(*slow_com_header);
139 
140 	/*
141 	 * Sanity checking of the header.
142 	 */
143 	if (slow_com_header->proto_subtype == SLOW_PROTO_LACP &&
144 		slow_com_header->version != LACP_VERSION) {
145 		printf("LACP version %u packet not supported",
146 		    slow_com_header->version);
147 		return;
148 	}
149 	if (slow_com_header->proto_subtype == SLOW_PROTO_MARKER &&
150 		slow_com_header->version != MARKER_VERSION) {
151 		printf("MARKER version %u packet not supported",
152 		    slow_com_header->version);
153 		return;
154 	}
155 
156 	printf("%sv%u, length: %u",
157 	    tok2str(slow_proto_values, "unknown (%u)",
158 	    slow_com_header->proto_subtype), slow_com_header->version, len);
159 
160 	if (!vflag)
161 		return;
162 
163 	/* ok they seem to want to know everything - lets fully decode it */
164 	tlen = len - sizeof(struct slow_common_header);
165 	tptr += sizeof(const struct slow_common_header);
166 
167 	while (tlen > 0) {
168 		/* did we capture enough for fully decoding the tlv header ? */
169 		TCHECK2(*tptr, sizeof(struct tlv_header_t));
170 		tlv_header = (const struct tlv_header_t *)tptr;
171 		tlv_len = tlv_header->length;
172 
173 		/* End of message */
174 		if (tlv_header->type == LACP_TLV_TERMINATOR ||
175 		    tlv_header->type == MARKER_TLV_TERMINATOR)
176 			return;
177 
178 		printf("\n\t%s TLV (0x%02x), length: %u",
179 		    tok2str(slow_tlv_values, "Unknown",
180 		    (slow_com_header->proto_subtype << 8) + tlv_header->type),
181 		    tlv_header->type, tlv_len);
182 
183 		if (tlv_len < sizeof(struct tlv_header_t) || tlv_len > tlen) {
184 			printf("\n\tInvalid TLV length: %u", tlv_len);
185 			return;
186 		}
187 
188 		tlv_tptr = tptr + sizeof(struct tlv_header_t);
189 		tlv_tlen = tlv_len - sizeof(struct tlv_header_t);
190 
191 		/* did we capture enough for fully decoding the tlv ? */
192 		TCHECK2(*tptr, tlv_len);
193 
194 		switch((slow_com_header->proto_subtype << 8) +
195 		    tlv_header->type) {
196 
197 		/* those two TLVs have the same structure -> fall through */
198 		case ((SLOW_PROTO_LACP << 8) + LACP_TLV_ACTOR_INFO):
199 		case ((SLOW_PROTO_LACP << 8) + LACP_TLV_PARTNER_INFO):
200 			tlv_ptr.actor_partner_info =
201 			    (struct lacp_tlv_actor_partner_info_t *)tlv_tptr;
202 			if (tlv_tlen != sizeof(*tlv_ptr.actor_partner_info)) {
203 				printf("\n\tInvalid partner/actor info length %u",
204 				    tlv_tlen);
205 				break;
206 			}
207 
208 			printf("\n\t  System %s, System Priority %u, Key %u"
209 			    ", Port %u, Port Priority %u\n\t  ",
210 			    etheraddr_string(tlv_ptr.actor_partner_info->sys),
211 			    EXTRACT_16BITS(tlv_ptr.actor_partner_info->sys_pri),
212 			    EXTRACT_16BITS(tlv_ptr.actor_partner_info->key),
213 			    EXTRACT_16BITS(tlv_ptr.actor_partner_info->port),
214 			    EXTRACT_16BITS(tlv_ptr.actor_partner_info->
215 			    port_pri));
216 			printb("State", tlv_ptr.actor_partner_info->state,
217 			    ACTOR_PARTNER_BITS);
218 			break;
219 
220 		case ((SLOW_PROTO_LACP << 8) + LACP_TLV_COLLECTOR_INFO):
221 			tlv_ptr.collector_info =
222 			    (struct lacp_tlv_collector_info_t *)tlv_tptr;
223 			if (tlv_tlen != sizeof(*tlv_ptr.collector_info)) {
224 				printf("\n\tInvalid collector info length %u",
225 				    tlv_tlen);
226 				break;
227 			}
228 
229 			printf("\n\t  Max Delay %u",
230 			    EXTRACT_16BITS(tlv_ptr.collector_info->max_delay));
231 			break;
232 
233 		case ((SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_INFO):
234 		case ((SLOW_PROTO_MARKER << 8) + MARKER_TLV_MARKER_RESP):
235 			tlv_ptr.marker_tlv_marker_info =
236 			    (struct marker_tlv_marker_info_t *)tlv_tptr;
237 			if (tlv_tlen !=
238 			    sizeof(*tlv_ptr.marker_tlv_marker_info)) {
239 				printf("\n\tInvalid marker info/resp length %u",
240 				    tlv_tlen);
241 				break;
242 			}
243 
244 			printf("\n\t  Request System %s, Request Port %u,"
245 			    " Request Transaction ID 0x%08x",
246 			    etheraddr_string(tlv_ptr.marker_tlv_marker_info->
247 			    req_sys),
248 			    EXTRACT_16BITS(tlv_ptr.marker_tlv_marker_info->
249 			    req_port),
250 			    EXTRACT_32BITS(tlv_ptr.marker_tlv_marker_info->
251 			    req_trans_id));
252 			break;
253 
254 		default:
255 			if (vflag > 1)
256 				printf("\n\t Unknown TLV type: 0x%x \n",
257 				    (slow_com_header->proto_subtype << 8) +
258 				    tlv_header->type);
259 			break;
260 		}
261 
262 		tptr += tlv_len;
263 		tlen -= tlv_len;
264 	}
265 
266     return;
267 trunc:
268     printf("\n\t[|slow]");
269 }
270