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