1 /* $OpenBSD: print-stp.c,v 1.12 2023/09/06 05:54:07 jsg Exp $ */ 2 3 /* 4 * Copyright (c) 2000 Jason L. Wright (jason@thought.net) 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Pretty print 802.1D Bridge Protocol Data Units 31 */ 32 33 #include <sys/time.h> 34 #include <sys/socket.h> 35 #include <sys/file.h> 36 #include <sys/ioctl.h> 37 38 #include <net/if.h> 39 40 #include <netinet/in.h> 41 #include <netinet/ip.h> 42 43 #include <ctype.h> 44 #include <netdb.h> 45 #include <pcap.h> 46 #include <signal.h> 47 #include <stdio.h> 48 49 #include <netinet/if_ether.h> 50 #include "ethertype.h" 51 52 #include <net/ppp_defs.h> 53 #include "interface.h" 54 #include "addrtoname.h" 55 #include "extract.h" 56 #include "llc.h" 57 58 #define STP_MSGTYPE_CBPDU 0x00 59 #define STP_MSGTYPE_RSTP 0x02 60 #define STP_MSGTYPE_TBPDU 0x80 61 62 #define STP_FLAGS_STPMASK 0x81 /* strip unused STP flags */ 63 #define STP_FLAGS_RSTPMASK 0x7f /* strip unused RSTP flags */ 64 #define STP_FLAGS_TC 0x01 /* Topology change */ 65 #define STP_FLAGS_P 0x02 /* Proposal flag */ 66 #define STP_FLAGS_ROLE 0x0c /* Port Role */ 67 #define STP_FLAGS_ROLE_S 2 /* Port Role offset */ 68 #define STP_FLAGS_ROLE_ALT 1 /* Alt/Backup port */ 69 #define STP_FLAGS_ROLE_ROOT 2 /* Root port */ 70 #define STP_FLAGS_ROLE_DESG 3 /* Designated port */ 71 #define STP_FLAGS_L 0x10 /* Learning flag */ 72 #define STP_FLAGS_F 0x20 /* Forwarding flag */ 73 #define STP_FLAGS_A 0x40 /* Agreement flag */ 74 #define STP_FLAGS_TCA 0x80 /* Topology change ack */ 75 #define STP_FLAGS_BITS \ 76 "\20\1TC\2PROPOSAL\5LEARNING\6FORWARDING\7AGREED\10TCACK" 77 78 enum { 79 STP_PROTO_STP = 0x00, 80 STP_PROTO_RSTP = 0x02, 81 STP_PROTO_SSTP = 0x10 /* Cizzco-Eeeh */ 82 }; 83 84 static void stp_print_cbpdu(const u_char *, u_int, int); 85 static void stp_print_tbpdu(const u_char *, u_int); 86 87 void 88 stp_print(const u_char *p, u_int len) 89 { 90 u_int16_t id; 91 int proto = STP_PROTO_STP; 92 93 if (len < 3) 94 goto truncated; 95 if (p[0] == LLCSAP_8021D && p[1] == LLCSAP_8021D && p[2] == LLC_UI) 96 printf("802.1d"); 97 else if (p[0] == LLCSAP_SNAP && p[1] == LLCSAP_SNAP && p[2] == LLC_UI) { 98 proto = STP_PROTO_SSTP; 99 printf("SSTP"); 100 if (len < 8) 101 goto truncated; 102 p += 5; 103 len -= 5; 104 } else { 105 printf("invalid protocol"); 106 return; 107 } 108 p += 3; 109 len -= 3; 110 111 if (len < 3) 112 goto truncated; 113 id = EXTRACT_16BITS(p); 114 if (id != 0) { 115 printf(" unknown protocol id(0x%x)", id); 116 return; 117 } 118 switch (p[2]) { 119 case STP_PROTO_STP: 120 printf(" STP"); 121 break; 122 case STP_PROTO_RSTP: 123 printf(" RSTP"); 124 break; 125 default: 126 printf(" unknown protocol ver(0x%x)", p[2]); 127 return; 128 } 129 p += 3; 130 len -= 3; 131 132 if (len < 1) 133 goto truncated; 134 switch (*p) { 135 case STP_MSGTYPE_CBPDU: 136 stp_print_cbpdu(p, len, proto); 137 break; 138 case STP_MSGTYPE_RSTP: 139 stp_print_cbpdu(p, len, STP_PROTO_RSTP); 140 break; 141 case STP_MSGTYPE_TBPDU: 142 stp_print_tbpdu(p, len); 143 break; 144 default: 145 printf(" unknown message (0x%02x)", *p); 146 break; 147 } 148 149 return; 150 151 truncated: 152 printf("[|802.1d]"); 153 } 154 155 static void 156 stp_print_cbpdu(const u_char *p, u_int len, int proto) 157 { 158 u_int32_t cost; 159 u_int16_t t; 160 u_int8_t flags, role; 161 int x; 162 163 p += 1; 164 len -= 1; 165 166 printf(" config"); 167 168 if (len < 1) 169 goto truncated; 170 if (*p) { 171 switch (proto) { 172 case STP_PROTO_STP: 173 case STP_PROTO_SSTP: 174 flags = *p & STP_FLAGS_STPMASK; 175 role = STP_FLAGS_ROLE_DESG; 176 break; 177 case STP_PROTO_RSTP: 178 default: 179 flags = *p & STP_FLAGS_RSTPMASK; 180 role = (flags & STP_FLAGS_ROLE) >> STP_FLAGS_ROLE_S; 181 break; 182 } 183 184 printb(" flags", flags, STP_FLAGS_BITS); 185 switch (role) { 186 case STP_FLAGS_ROLE_ALT: 187 printf(" role=ALT/BACKUP"); 188 break; 189 case STP_FLAGS_ROLE_ROOT: 190 printf(" role=ROOT"); 191 break; 192 case STP_FLAGS_ROLE_DESG: 193 printf(" role=DESIGNATED"); 194 break; 195 } 196 } 197 p += 1; 198 len -= 1; 199 200 if (len < 8) 201 goto truncated; 202 printf(" root="); 203 printf("%x.", EXTRACT_16BITS(p)); 204 p += 2; 205 len -= 2; 206 for (x = 0; x < 6; x++) { 207 printf("%s%x", (x != 0) ? ":" : "", *p); 208 p++; 209 len--; 210 } 211 212 if (len < 4) 213 goto truncated; 214 cost = EXTRACT_32BITS(p); 215 printf(" rootcost=%u", cost); 216 p += 4; 217 len -= 4; 218 219 if (len < 8) 220 goto truncated; 221 printf(" bridge="); 222 printf("%x.", EXTRACT_16BITS(p)); 223 p += 2; 224 len -= 2; 225 for (x = 0; x < 6; x++) { 226 printf("%s%x", (x != 0) ? ":" : "", *p); 227 p++; 228 len--; 229 } 230 231 if (len < 2) 232 goto truncated; 233 t = EXTRACT_16BITS(p); 234 switch (proto) { 235 case STP_PROTO_STP: 236 case STP_PROTO_SSTP: 237 printf(" port=%u", t & 0xff); 238 printf(" ifcost=%u", t >> 8); 239 break; 240 case STP_PROTO_RSTP: 241 default: 242 printf(" port=%u", t & 0xfff); 243 printf(" ifcost=%u", t >> 8); 244 break; 245 } 246 p += 2; 247 len -= 2; 248 249 if (len < 2) 250 goto truncated; 251 printf(" age=%u/%u", p[0], p[1]); 252 p += 2; 253 len -= 2; 254 255 if (len < 2) 256 goto truncated; 257 printf(" max=%u/%u", p[0], p[1]); 258 p += 2; 259 len -= 2; 260 261 if (len < 2) 262 goto truncated; 263 printf(" hello=%u/%u", p[0], p[1]); 264 p += 2; 265 len -= 2; 266 267 if (len < 2) 268 goto truncated; 269 printf(" fwdelay=%u/%u", p[0], p[1]); 270 p += 2; 271 len -= 2; 272 273 if (proto == STP_PROTO_SSTP) { 274 if (len < 7) 275 goto truncated; 276 p += 1; 277 len -= 1; 278 if (EXTRACT_16BITS(p) == 0 && EXTRACT_16BITS(p + 2) == 0x02) { 279 printf(" pvid=%u", EXTRACT_16BITS(p + 4)); 280 p += 6; 281 len -= 6; 282 } 283 } 284 285 return; 286 287 truncated: 288 printf("[|802.1d]"); 289 } 290 291 static void 292 stp_print_tbpdu(const u_char *p, u_int len) 293 { 294 printf(" tcn"); 295 } 296