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