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