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