1 /* $OpenBSD: print-stp.c,v 1.6 2006/11/21 12:43:56 reyk 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/param.h> 34 #include <sys/time.h> 35 #include <sys/socket.h> 36 #include <sys/file.h> 37 #include <sys/ioctl.h> 38 39 struct mbuf; 40 struct rtentry; 41 #include <net/if.h> 42 43 #include <netinet/in.h> 44 #include <netinet/in_systm.h> 45 #include <netinet/ip.h> 46 47 #include <netipx/ipx.h> 48 #include <netipx/ipx_if.h> 49 50 #include <ctype.h> 51 #include <netdb.h> 52 #include <pcap.h> 53 #include <signal.h> 54 #include <stdio.h> 55 56 #include <netinet/if_ether.h> 57 #include "ethertype.h" 58 59 #include <net/ppp_defs.h> 60 #include "interface.h" 61 #include "addrtoname.h" 62 #include "extract.h" 63 #include "llc.h" 64 65 #define STP_MSGTYPE_CBPDU 0x00 66 #define STP_MSGTYPE_RSTP 0x02 67 #define STP_MSGTYPE_TBPDU 0x80 68 69 #define STP_FLAGS_STPMASK 0x81 /* strip unused STP flags */ 70 #define STP_FLAGS_RSTPMASK 0x7f /* strip unused RSTP flags */ 71 #define STP_FLAGS_TC 0x01 /* Topology change */ 72 #define STP_FLAGS_P 0x02 /* Proposal flag */ 73 #define STP_FLAGS_ROLE 0x0c /* Port Role */ 74 #define STP_FLAGS_ROLE_S 2 /* Port Role offset */ 75 #define STP_FLAGS_ROLE_ALT 1 /* Alt/Backup port */ 76 #define STP_FLAGS_ROLE_ROOT 2 /* Root port */ 77 #define STP_FLAGS_ROLE_DESG 3 /* Designated port */ 78 #define STP_FLAGS_L 0x10 /* Learning flag */ 79 #define STP_FLAGS_F 0x20 /* Forwarding flag */ 80 #define STP_FLAGS_A 0x40 /* Agreement flag */ 81 #define STP_FLAGS_TCA 0x80 /* Topology change ack */ 82 #define STP_FLAGS_BITS \ 83 "\20\1TC\2PROPOSAL\5LEARNING\6FORWARDING\7AGREED\10TCACK" 84 85 enum { 86 STP_PROTO_STP = 0x00, 87 STP_PROTO_RSTP = 0x02, 88 STP_PROTO_SSTP = 0x10 /* Cizzco-Eeeh */ 89 }; 90 91 static void stp_print_cbpdu(const u_char *, u_int, int); 92 static void stp_print_tbpdu(const u_char *, u_int); 93 94 void 95 stp_print(p, len) 96 const u_char *p; 97 u_int len; 98 { 99 u_int16_t id; 100 int proto = STP_PROTO_STP; 101 102 if (len < 3) 103 goto truncated; 104 if (p[0] == LLCSAP_8021D && p[1] == LLCSAP_8021D && p[2] == LLC_UI) 105 printf("802.1d"); 106 else if (p[0] == LLCSAP_SNAP && p[1] == LLCSAP_SNAP && p[2] == LLC_UI) { 107 proto = STP_PROTO_SSTP; 108 printf("SSTP"); 109 p += 5; 110 len -= 5; 111 } else { 112 printf("invalid protocol"); 113 return; 114 } 115 p += 3; 116 len -= 3; 117 118 if (len < 3) 119 goto truncated; 120 id = EXTRACT_16BITS(p); 121 if (id != 0) { 122 printf(" unknown protocol id(0x%x)", id); 123 return; 124 } 125 switch (p[2]) { 126 case STP_PROTO_STP: 127 printf(" STP"); 128 break; 129 case STP_PROTO_RSTP: 130 printf(" RSTP"); 131 break; 132 default: 133 printf(" unknown protocol ver(0x%x)", p[2]); 134 return; 135 } 136 p += 3; 137 len -= 3; 138 139 if (len < 1) 140 goto truncated; 141 switch (*p) { 142 case STP_MSGTYPE_CBPDU: 143 stp_print_cbpdu(p, len, proto); 144 break; 145 case STP_MSGTYPE_RSTP: 146 stp_print_cbpdu(p, len, STP_PROTO_RSTP); 147 break; 148 case STP_MSGTYPE_TBPDU: 149 stp_print_tbpdu(p, len); 150 break; 151 default: 152 printf(" unknown message (0x%02x)", *p); 153 break; 154 } 155 156 return; 157 158 truncated: 159 printf("[|802.1d]"); 160 } 161 162 static void 163 stp_print_cbpdu(p, len, proto) 164 const u_char *p; 165 u_int len; 166 int proto; 167 { 168 u_int32_t cost; 169 u_int16_t t; 170 u_int8_t flags, role; 171 int x; 172 173 p += 1; 174 len -= 1; 175 176 printf(" config"); 177 178 if (len < 1) 179 goto truncated; 180 if (*p) { 181 switch (proto) { 182 case STP_PROTO_STP: 183 case STP_PROTO_SSTP: 184 flags = *p & STP_FLAGS_STPMASK; 185 role = STP_FLAGS_ROLE_DESG; 186 break; 187 case STP_PROTO_RSTP: 188 default: 189 flags = *p & STP_FLAGS_RSTPMASK; 190 role = (flags & STP_FLAGS_ROLE) >> STP_FLAGS_ROLE_S; 191 break; 192 } 193 194 printb(" flags", flags, STP_FLAGS_BITS); 195 switch (role) { 196 case STP_FLAGS_ROLE_ALT: 197 printf(" role=ALT/BACKUP"); 198 break; 199 case STP_FLAGS_ROLE_ROOT: 200 printf(" role=ROOT"); 201 break; 202 case STP_FLAGS_ROLE_DESG: 203 printf(" role=DESIGNATED"); 204 break; 205 } 206 } 207 p += 1; 208 len -= 1; 209 210 if (len < 8) 211 goto truncated; 212 printf(" root="); 213 printf("%x.", EXTRACT_16BITS(p)); 214 p += 2; 215 len -= 2; 216 for (x = 0; x < 6; x++) { 217 printf("%s%x", (x != 0) ? ":" : "", *p); 218 p++; 219 len--; 220 } 221 222 if (len < 4) 223 goto truncated; 224 cost = EXTRACT_32BITS(p); 225 printf(" rootcost=%u", cost); 226 p += 4; 227 len -= 4; 228 229 if (len < 8) 230 goto truncated; 231 printf(" bridge="); 232 printf("%x.", EXTRACT_16BITS(p)); 233 p += 2; 234 len -= 2; 235 for (x = 0; x < 6; x++) { 236 printf("%s%x", (x != 0) ? ":" : "", *p); 237 p++; 238 len--; 239 } 240 241 if (len < 2) 242 goto truncated; 243 t = EXTRACT_16BITS(p); 244 switch (proto) { 245 case STP_PROTO_STP: 246 case STP_PROTO_SSTP: 247 printf(" port=%u", t & 0xff); 248 printf(" ifcost=%u", t >> 8); 249 break; 250 case STP_PROTO_RSTP: 251 default: 252 printf(" port=%u", t & 0xfff); 253 printf(" ifcost=%u", t >> 8); 254 break; 255 } 256 p += 2; 257 len -= 2; 258 259 if (len < 2) 260 goto truncated; 261 printf(" age=%u/%u", p[0], p[1]); 262 p += 2; 263 len -= 2; 264 265 if (len < 2) 266 goto truncated; 267 printf(" max=%u/%u", p[0], p[1]); 268 p += 2; 269 len -= 2; 270 271 if (len < 2) 272 goto truncated; 273 printf(" hello=%u/%u", p[0], p[1]); 274 p += 2; 275 len -= 2; 276 277 if (len < 2) 278 goto truncated; 279 printf(" fwdelay=%u/%u", p[0], p[1]); 280 p += 2; 281 len -= 2; 282 283 if (proto == STP_PROTO_SSTP) { 284 if (len < 7) 285 goto truncated; 286 p += 1; 287 len -= 1; 288 if (EXTRACT_16BITS(p) == 0 && EXTRACT_16BITS(p + 2) == 0x02) { 289 printf(" pvid=%u", EXTRACT_16BITS(p + 4)); 290 p += 6; 291 len -= 6; 292 } 293 } 294 295 return; 296 297 truncated: 298 printf("[|802.1d]"); 299 } 300 301 static void 302 stp_print_tbpdu(p, len) 303 const u_char *p; 304 u_int len; 305 { 306 printf(" tcn"); 307 } 308