1 /* 2 * Redistribution and use in source and binary forms, with or without 3 * modification, are permitted provided that: (1) source code 4 * distributions retain the above copyright notice and this paragraph 5 * in its entirety, and (2) distributions including binary code include 6 * the above copyright notice and this paragraph in its entirety in 7 * the documentation or other materials provided with the distribution. 8 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 9 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 10 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 11 * FOR A PARTICULAR PURPOSE. 12 * 13 * Original code by Hannes Gredler (hannes@juniper.net) 14 */ 15 16 #include <sys/cdefs.h> 17 #ifndef lint 18 __RCSID("$NetBSD: print-bfd.c,v 1.4 2014/11/20 03:05:03 christos Exp $"); 19 #endif 20 21 #define NETDISSECT_REWORKED 22 #ifdef HAVE_CONFIG_H 23 #include "config.h" 24 #endif 25 26 #include <tcpdump-stdinc.h> 27 28 #include "interface.h" 29 #include "extract.h" 30 31 #include "udp.h" 32 33 /* 34 * Control packet, BFDv0, draft-katz-ward-bfd-01.txt 35 * 36 * 0 1 2 3 37 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 38 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 39 * |Vers | Diag |H|D|P|F| Rsvd | Detect Mult | Length | 40 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 41 * | My Discriminator | 42 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 43 * | Your Discriminator | 44 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 45 * | Desired Min TX Interval | 46 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 47 * | Required Min RX Interval | 48 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 49 * | Required Min Echo RX Interval | 50 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 51 */ 52 53 /* 54 * Control packet, BFDv1, draft-ietf-bfd-base-02.txt 55 * 56 * 0 1 2 3 57 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 58 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 59 * |Vers | Diag |Sta|P|F|C|A|D|R| Detect Mult | Length | 60 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 61 * | My Discriminator | 62 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 63 * | Your Discriminator | 64 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 65 * | Desired Min TX Interval | 66 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 67 * | Required Min RX Interval | 68 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 69 * | Required Min Echo RX Interval | 70 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 71 */ 72 73 struct bfd_header_t { 74 uint8_t version_diag; 75 uint8_t flags; 76 uint8_t detect_time_multiplier; 77 uint8_t length; 78 uint8_t my_discriminator[4]; 79 uint8_t your_discriminator[4]; 80 uint8_t desired_min_tx_interval[4]; 81 uint8_t required_min_rx_interval[4]; 82 uint8_t required_min_echo_interval[4]; 83 }; 84 85 /* 86 * An optional Authentication Header may be present 87 * 88 * 0 1 2 3 89 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 90 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 91 * | Auth Type | Auth Len | Authentication Data... | 92 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 93 */ 94 95 struct bfd_auth_header_t { 96 uint8_t auth_type; 97 uint8_t auth_len; 98 uint8_t auth_data; 99 }; 100 101 static const struct tok bfd_v1_authentication_values[] = { 102 { 0, "Reserved" }, 103 { 1, "Simple Password" }, 104 { 2, "Keyed MD5" }, 105 { 3, "Meticulous Keyed MD5" }, 106 { 4, "Keyed SHA1" }, 107 { 5, "Meticulous Keyed SHA1" }, 108 { 0, NULL } 109 }; 110 111 #define BFD_EXTRACT_VERSION(x) (((x)&0xe0)>>5) 112 #define BFD_EXTRACT_DIAG(x) ((x)&0x1f) 113 114 static const struct tok bfd_port_values[] = { 115 { BFD_CONTROL_PORT, "Control" }, 116 { BFD_ECHO_PORT, "Echo" }, 117 { 0, NULL } 118 }; 119 120 121 static const struct tok bfd_diag_values[] = { 122 { 0, "No Diagnostic" }, 123 { 1, "Control Detection Time Expired" }, 124 { 2, "Echo Function Failed" }, 125 { 3, "Neighbor Signaled Session Down" }, 126 { 4, "Forwarding Plane Reset" }, 127 { 5, "Path Down" }, 128 { 6, "Concatenated Path Down" }, 129 { 7, "Administratively Down" }, 130 { 8, "Reverse Concatenated Path Down" }, 131 { 0, NULL } 132 }; 133 134 static const struct tok bfd_v0_flag_values[] = { 135 { 0x80, "I Hear You" }, 136 { 0x40, "Demand" }, 137 { 0x20, "Poll" }, 138 { 0x10, "Final" }, 139 { 0x08, "Reserved" }, 140 { 0x04, "Reserved" }, 141 { 0x02, "Reserved" }, 142 { 0x01, "Reserved" }, 143 { 0, NULL } 144 }; 145 146 #define BFD_FLAG_AUTH 0x04 147 148 static const struct tok bfd_v1_flag_values[] = { 149 { 0x20, "Poll" }, 150 { 0x10, "Final" }, 151 { 0x08, "Control Plane Independent" }, 152 { BFD_FLAG_AUTH, "Authentication Present" }, 153 { 0x02, "Demand" }, 154 { 0x01, "Reserved" }, 155 { 0, NULL } 156 }; 157 158 static const struct tok bfd_v1_state_values[] = { 159 { 0, "AdminDown" }, 160 { 1, "Down" }, 161 { 2, "Init" }, 162 { 3, "Up" }, 163 { 0, NULL } 164 }; 165 166 void 167 bfd_print(netdissect_options *ndo, register const u_char *pptr, 168 register u_int len, register u_int port) 169 { 170 const struct bfd_header_t *bfd_header; 171 const struct bfd_auth_header_t *bfd_auth_header; 172 uint8_t version = 0; 173 174 bfd_header = (const struct bfd_header_t *)pptr; 175 if (port == BFD_CONTROL_PORT) { 176 ND_TCHECK(*bfd_header); 177 version = BFD_EXTRACT_VERSION(bfd_header->version_diag); 178 } else if (port == BFD_ECHO_PORT) { 179 /* Echo is BFD v1 only */ 180 version = 1; 181 } 182 switch ((port << 8) | version) { 183 184 /* BFDv0 */ 185 case (BFD_CONTROL_PORT << 8): 186 if (ndo->ndo_vflag < 1) 187 { 188 ND_PRINT((ndo, "BFDv%u, %s, Flags: [%s], length: %u", 189 version, 190 tok2str(bfd_port_values, "unknown (%u)", port), 191 bittok2str(bfd_v0_flag_values, "none", bfd_header->flags), 192 len)); 193 return; 194 } 195 196 ND_PRINT((ndo, "BFDv%u, length: %u\n\t%s, Flags: [%s], Diagnostic: %s (0x%02x)", 197 version, 198 len, 199 tok2str(bfd_port_values, "unknown (%u)", port), 200 bittok2str(bfd_v0_flag_values, "none", bfd_header->flags), 201 tok2str(bfd_diag_values,"unknown",BFD_EXTRACT_DIAG(bfd_header->version_diag)), 202 BFD_EXTRACT_DIAG(bfd_header->version_diag))); 203 204 ND_PRINT((ndo, "\n\tDetection Timer Multiplier: %u (%u ms Detection time), BFD Length: %u", 205 bfd_header->detect_time_multiplier, 206 bfd_header->detect_time_multiplier * EXTRACT_32BITS(bfd_header->desired_min_tx_interval)/1000, 207 bfd_header->length)); 208 209 210 ND_PRINT((ndo, "\n\tMy Discriminator: 0x%08x", EXTRACT_32BITS(bfd_header->my_discriminator))); 211 ND_PRINT((ndo, ", Your Discriminator: 0x%08x", EXTRACT_32BITS(bfd_header->your_discriminator))); 212 ND_PRINT((ndo, "\n\t Desired min Tx Interval: %4u ms", EXTRACT_32BITS(bfd_header->desired_min_tx_interval)/1000)); 213 ND_PRINT((ndo, "\n\t Required min Rx Interval: %4u ms", EXTRACT_32BITS(bfd_header->required_min_rx_interval)/1000)); 214 ND_PRINT((ndo, "\n\t Required min Echo Interval: %4u ms", EXTRACT_32BITS(bfd_header->required_min_echo_interval)/1000)); 215 break; 216 217 /* BFDv1 */ 218 case (BFD_CONTROL_PORT << 8 | 1): 219 if (ndo->ndo_vflag < 1) 220 { 221 ND_PRINT((ndo, "BFDv%u, %s, State %s, Flags: [%s], length: %u", 222 version, 223 tok2str(bfd_port_values, "unknown (%u)", port), 224 tok2str(bfd_v1_state_values, "unknown (%u)", (bfd_header->flags & 0xc0) >> 6), 225 bittok2str(bfd_v1_flag_values, "none", bfd_header->flags & 0x3f), 226 len)); 227 return; 228 } 229 230 ND_PRINT((ndo, "BFDv%u, length: %u\n\t%s, State %s, Flags: [%s], Diagnostic: %s (0x%02x)", 231 version, 232 len, 233 tok2str(bfd_port_values, "unknown (%u)", port), 234 tok2str(bfd_v1_state_values, "unknown (%u)", (bfd_header->flags & 0xc0) >> 6), 235 bittok2str(bfd_v1_flag_values, "none", bfd_header->flags & 0x3f), 236 tok2str(bfd_diag_values,"unknown",BFD_EXTRACT_DIAG(bfd_header->version_diag)), 237 BFD_EXTRACT_DIAG(bfd_header->version_diag))); 238 239 ND_PRINT((ndo, "\n\tDetection Timer Multiplier: %u (%u ms Detection time), BFD Length: %u", 240 bfd_header->detect_time_multiplier, 241 bfd_header->detect_time_multiplier * EXTRACT_32BITS(bfd_header->desired_min_tx_interval)/1000, 242 bfd_header->length)); 243 244 245 ND_PRINT((ndo, "\n\tMy Discriminator: 0x%08x", EXTRACT_32BITS(bfd_header->my_discriminator))); 246 ND_PRINT((ndo, ", Your Discriminator: 0x%08x", EXTRACT_32BITS(bfd_header->your_discriminator))); 247 ND_PRINT((ndo, "\n\t Desired min Tx Interval: %4u ms", EXTRACT_32BITS(bfd_header->desired_min_tx_interval)/1000)); 248 ND_PRINT((ndo, "\n\t Required min Rx Interval: %4u ms", EXTRACT_32BITS(bfd_header->required_min_rx_interval)/1000)); 249 ND_PRINT((ndo, "\n\t Required min Echo Interval: %4u ms", EXTRACT_32BITS(bfd_header->required_min_echo_interval)/1000)); 250 251 if (bfd_header->flags & BFD_FLAG_AUTH) { 252 pptr += sizeof (const struct bfd_header_t); 253 bfd_auth_header = (const struct bfd_auth_header_t *)pptr; 254 ND_TCHECK2(*bfd_auth_header, sizeof(const struct bfd_auth_header_t)); 255 ND_PRINT((ndo, "\n\t%s (%u) Authentication, length %u present", 256 tok2str(bfd_v1_authentication_values,"Unknown",bfd_auth_header->auth_type), 257 bfd_auth_header->auth_type, 258 bfd_auth_header->auth_len)); 259 } 260 break; 261 262 /* BFDv0 */ 263 case (BFD_ECHO_PORT << 8): /* not yet supported - fall through */ 264 /* BFDv1 */ 265 case (BFD_ECHO_PORT << 8 | 1): 266 267 default: 268 ND_PRINT((ndo, "BFD, %s, length: %u", 269 tok2str(bfd_port_values, "unknown (%u)", port), 270 len)); 271 if (ndo->ndo_vflag >= 1) { 272 if(!print_unknown_data(ndo, pptr,"\n\t",len)) 273 return; 274 } 275 break; 276 } 277 return; 278 279 trunc: 280 ND_PRINT((ndo, "[|BFD]")); 281 } 282 /* 283 * Local Variables: 284 * c-style: whitesmith 285 * c-basic-offset: 8 286 * End: 287 */ 288