1 /* $OpenBSD: print-stp.c,v 1.10 2021/12/01 18:28:46 deraadt 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(p, len) 89 const u_char *p; 90 u_int len; 91 { 92 u_int16_t id; 93 int proto = STP_PROTO_STP; 94 95 if (len < 3) 96 goto truncated; 97 if (p[0] == LLCSAP_8021D && p[1] == LLCSAP_8021D && p[2] == LLC_UI) 98 printf("802.1d"); 99 else if (p[0] == LLCSAP_SNAP && p[1] == LLCSAP_SNAP && p[2] == LLC_UI) { 100 proto = STP_PROTO_SSTP; 101 printf("SSTP"); 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(p, len, proto) 157 const u_char *p; 158 u_int len; 159 int proto; 160 { 161 u_int32_t cost; 162 u_int16_t t; 163 u_int8_t flags, role; 164 int x; 165 166 p += 1; 167 len -= 1; 168 169 printf(" config"); 170 171 if (len < 1) 172 goto truncated; 173 if (*p) { 174 switch (proto) { 175 case STP_PROTO_STP: 176 case STP_PROTO_SSTP: 177 flags = *p & STP_FLAGS_STPMASK; 178 role = STP_FLAGS_ROLE_DESG; 179 break; 180 case STP_PROTO_RSTP: 181 default: 182 flags = *p & STP_FLAGS_RSTPMASK; 183 role = (flags & STP_FLAGS_ROLE) >> STP_FLAGS_ROLE_S; 184 break; 185 } 186 187 printb(" flags", flags, STP_FLAGS_BITS); 188 switch (role) { 189 case STP_FLAGS_ROLE_ALT: 190 printf(" role=ALT/BACKUP"); 191 break; 192 case STP_FLAGS_ROLE_ROOT: 193 printf(" role=ROOT"); 194 break; 195 case STP_FLAGS_ROLE_DESG: 196 printf(" role=DESIGNATED"); 197 break; 198 } 199 } 200 p += 1; 201 len -= 1; 202 203 if (len < 8) 204 goto truncated; 205 printf(" root="); 206 printf("%x.", EXTRACT_16BITS(p)); 207 p += 2; 208 len -= 2; 209 for (x = 0; x < 6; x++) { 210 printf("%s%x", (x != 0) ? ":" : "", *p); 211 p++; 212 len--; 213 } 214 215 if (len < 4) 216 goto truncated; 217 cost = EXTRACT_32BITS(p); 218 printf(" rootcost=%u", cost); 219 p += 4; 220 len -= 4; 221 222 if (len < 8) 223 goto truncated; 224 printf(" bridge="); 225 printf("%x.", EXTRACT_16BITS(p)); 226 p += 2; 227 len -= 2; 228 for (x = 0; x < 6; x++) { 229 printf("%s%x", (x != 0) ? ":" : "", *p); 230 p++; 231 len--; 232 } 233 234 if (len < 2) 235 goto truncated; 236 t = EXTRACT_16BITS(p); 237 switch (proto) { 238 case STP_PROTO_STP: 239 case STP_PROTO_SSTP: 240 printf(" port=%u", t & 0xff); 241 printf(" ifcost=%u", t >> 8); 242 break; 243 case STP_PROTO_RSTP: 244 default: 245 printf(" port=%u", t & 0xfff); 246 printf(" ifcost=%u", t >> 8); 247 break; 248 } 249 p += 2; 250 len -= 2; 251 252 if (len < 2) 253 goto truncated; 254 printf(" age=%u/%u", p[0], p[1]); 255 p += 2; 256 len -= 2; 257 258 if (len < 2) 259 goto truncated; 260 printf(" max=%u/%u", p[0], p[1]); 261 p += 2; 262 len -= 2; 263 264 if (len < 2) 265 goto truncated; 266 printf(" hello=%u/%u", p[0], p[1]); 267 p += 2; 268 len -= 2; 269 270 if (len < 2) 271 goto truncated; 272 printf(" fwdelay=%u/%u", p[0], p[1]); 273 p += 2; 274 len -= 2; 275 276 if (proto == STP_PROTO_SSTP) { 277 if (len < 7) 278 goto truncated; 279 p += 1; 280 len -= 1; 281 if (EXTRACT_16BITS(p) == 0 && EXTRACT_16BITS(p + 2) == 0x02) { 282 printf(" pvid=%u", EXTRACT_16BITS(p + 4)); 283 p += 6; 284 len -= 6; 285 } 286 } 287 288 return; 289 290 truncated: 291 printf("[|802.1d]"); 292 } 293 294 static void 295 stp_print_tbpdu(p, len) 296 const u_char *p; 297 u_int len; 298 { 299 printf(" tcn"); 300 } 301