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