print-ldp.c revision 1.4.8.1 1 1.1 christos /*
2 1.1 christos * Redistribution and use in source and binary forms, with or without
3 1.1 christos * modification, are permitted provided that: (1) source code
4 1.1 christos * distributions retain the above copyright notice and this paragraph
5 1.1 christos * in its entirety, and (2) distributions including binary code include
6 1.1 christos * the above copyright notice and this paragraph in its entirety in
7 1.1 christos * the documentation or other materials provided with the distribution.
8 1.1 christos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
9 1.1 christos * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
10 1.1 christos * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
11 1.1 christos * FOR A PARTICULAR PURPOSE.
12 1.1 christos *
13 1.1 christos * Original code by Hannes Gredler (hannes (at) juniper.net)
14 1.1 christos * and Steinar Haug (sthaug (at) nethelp.no)
15 1.1 christos */
16 1.1 christos
17 1.2 christos #include <sys/cdefs.h>
18 1.1 christos #ifndef lint
19 1.4.8.1 snj __RCSID("$NetBSD: print-ldp.c,v 1.4.8.1 2017/02/19 04:59:45 snj Exp $");
20 1.1 christos #endif
21 1.1 christos
22 1.4.8.1 snj /* \summary: Label Distribution Protocol (LDP) printer */
23 1.4.8.1 snj
24 1.1 christos #ifdef HAVE_CONFIG_H
25 1.1 christos #include "config.h"
26 1.1 christos #endif
27 1.1 christos
28 1.4.8.1 snj #include <netdissect-stdinc.h>
29 1.1 christos
30 1.4.8.1 snj #include "netdissect.h"
31 1.1 christos #include "extract.h"
32 1.1 christos #include "addrtoname.h"
33 1.1 christos
34 1.1 christos #include "l2vpn.h"
35 1.1 christos #include "af.h"
36 1.1 christos
37 1.1 christos /*
38 1.1 christos * ldp common header
39 1.1 christos *
40 1.1 christos * 0 1 2 3
41 1.1 christos * 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
42 1.1 christos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43 1.1 christos * | Version | PDU Length |
44 1.1 christos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45 1.1 christos * | LDP Identifier |
46 1.1 christos * + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47 1.1 christos * | |
48 1.1 christos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49 1.1 christos *
50 1.1 christos */
51 1.1 christos
52 1.1 christos struct ldp_common_header {
53 1.4.8.1 snj uint8_t version[2];
54 1.4.8.1 snj uint8_t pdu_length[2];
55 1.4.8.1 snj uint8_t lsr_id[4];
56 1.4.8.1 snj uint8_t label_space[2];
57 1.1 christos };
58 1.1 christos
59 1.1 christos #define LDP_VERSION 1
60 1.1 christos
61 1.1 christos /*
62 1.1 christos * ldp message header
63 1.1 christos *
64 1.1 christos * 0 1 2 3
65 1.1 christos * 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
66 1.1 christos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
67 1.1 christos * |U| Message Type | Message Length |
68 1.1 christos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
69 1.1 christos * | Message ID |
70 1.1 christos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
71 1.1 christos * | |
72 1.1 christos * + +
73 1.1 christos * | Mandatory Parameters |
74 1.1 christos * + +
75 1.1 christos * | |
76 1.1 christos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
77 1.1 christos * | |
78 1.1 christos * + +
79 1.1 christos * | Optional Parameters |
80 1.1 christos * + +
81 1.1 christos * | |
82 1.1 christos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
83 1.1 christos */
84 1.1 christos
85 1.1 christos struct ldp_msg_header {
86 1.4.8.1 snj uint8_t type[2];
87 1.4.8.1 snj uint8_t length[2];
88 1.4.8.1 snj uint8_t id[4];
89 1.1 christos };
90 1.1 christos
91 1.4.8.1 snj #define LDP_MASK_MSG_TYPE(x) ((x)&0x7fff)
92 1.4.8.1 snj #define LDP_MASK_U_BIT(x) ((x)&0x8000)
93 1.1 christos
94 1.1 christos #define LDP_MSG_NOTIF 0x0001
95 1.1 christos #define LDP_MSG_HELLO 0x0100
96 1.1 christos #define LDP_MSG_INIT 0x0200
97 1.1 christos #define LDP_MSG_KEEPALIVE 0x0201
98 1.1 christos #define LDP_MSG_ADDRESS 0x0300
99 1.1 christos #define LDP_MSG_ADDRESS_WITHDRAW 0x0301
100 1.1 christos #define LDP_MSG_LABEL_MAPPING 0x0400
101 1.1 christos #define LDP_MSG_LABEL_REQUEST 0x0401
102 1.1 christos #define LDP_MSG_LABEL_WITHDRAW 0x0402
103 1.1 christos #define LDP_MSG_LABEL_RELEASE 0x0403
104 1.1 christos #define LDP_MSG_LABEL_ABORT_REQUEST 0x0404
105 1.1 christos
106 1.1 christos #define LDP_VENDOR_PRIVATE_MIN 0x3e00
107 1.1 christos #define LDP_VENDOR_PRIVATE_MAX 0x3eff
108 1.1 christos #define LDP_EXPERIMENTAL_MIN 0x3f00
109 1.1 christos #define LDP_EXPERIMENTAL_MAX 0x3fff
110 1.1 christos
111 1.1 christos static const struct tok ldp_msg_values[] = {
112 1.1 christos { LDP_MSG_NOTIF, "Notification" },
113 1.1 christos { LDP_MSG_HELLO, "Hello" },
114 1.1 christos { LDP_MSG_INIT, "Initialization" },
115 1.1 christos { LDP_MSG_KEEPALIVE, "Keepalive" },
116 1.1 christos { LDP_MSG_ADDRESS, "Address" },
117 1.1 christos { LDP_MSG_ADDRESS_WITHDRAW, "Address Withdraw" },
118 1.1 christos { LDP_MSG_LABEL_MAPPING, "Label Mapping" },
119 1.1 christos { LDP_MSG_LABEL_REQUEST, "Label Request" },
120 1.1 christos { LDP_MSG_LABEL_WITHDRAW, "Label Withdraw" },
121 1.1 christos { LDP_MSG_LABEL_RELEASE, "Label Release" },
122 1.1 christos { LDP_MSG_LABEL_ABORT_REQUEST, "Label Abort Request" },
123 1.1 christos { 0, NULL}
124 1.1 christos };
125 1.1 christos
126 1.4.8.1 snj #define LDP_MASK_TLV_TYPE(x) ((x)&0x3fff)
127 1.4.8.1 snj #define LDP_MASK_F_BIT(x) ((x)&0x4000)
128 1.1 christos
129 1.1 christos #define LDP_TLV_FEC 0x0100
130 1.1 christos #define LDP_TLV_ADDRESS_LIST 0x0101
131 1.1 christos #define LDP_TLV_ADDRESS_LIST_AFNUM_LEN 2
132 1.1 christos #define LDP_TLV_HOP_COUNT 0x0103
133 1.1 christos #define LDP_TLV_PATH_VECTOR 0x0104
134 1.1 christos #define LDP_TLV_GENERIC_LABEL 0x0200
135 1.1 christos #define LDP_TLV_ATM_LABEL 0x0201
136 1.1 christos #define LDP_TLV_FR_LABEL 0x0202
137 1.1 christos #define LDP_TLV_STATUS 0x0300
138 1.1 christos #define LDP_TLV_EXTD_STATUS 0x0301
139 1.1 christos #define LDP_TLV_RETURNED_PDU 0x0302
140 1.1 christos #define LDP_TLV_RETURNED_MSG 0x0303
141 1.1 christos #define LDP_TLV_COMMON_HELLO 0x0400
142 1.1 christos #define LDP_TLV_IPV4_TRANSPORT_ADDR 0x0401
143 1.1 christos #define LDP_TLV_CONFIG_SEQ_NUMBER 0x0402
144 1.1 christos #define LDP_TLV_IPV6_TRANSPORT_ADDR 0x0403
145 1.1 christos #define LDP_TLV_COMMON_SESSION 0x0500
146 1.1 christos #define LDP_TLV_ATM_SESSION_PARM 0x0501
147 1.1 christos #define LDP_TLV_FR_SESSION_PARM 0x0502
148 1.1 christos #define LDP_TLV_FT_SESSION 0x0503
149 1.1 christos #define LDP_TLV_LABEL_REQUEST_MSG_ID 0x0600
150 1.1 christos #define LDP_TLV_MTU 0x0601 /* rfc 3988 */
151 1.1 christos
152 1.1 christos static const struct tok ldp_tlv_values[] = {
153 1.1 christos { LDP_TLV_FEC, "FEC" },
154 1.1 christos { LDP_TLV_ADDRESS_LIST, "Address List" },
155 1.1 christos { LDP_TLV_HOP_COUNT, "Hop Count" },
156 1.1 christos { LDP_TLV_PATH_VECTOR, "Path Vector" },
157 1.1 christos { LDP_TLV_GENERIC_LABEL, "Generic Label" },
158 1.1 christos { LDP_TLV_ATM_LABEL, "ATM Label" },
159 1.1 christos { LDP_TLV_FR_LABEL, "Frame-Relay Label" },
160 1.1 christos { LDP_TLV_STATUS, "Status" },
161 1.1 christos { LDP_TLV_EXTD_STATUS, "Extended Status" },
162 1.1 christos { LDP_TLV_RETURNED_PDU, "Returned PDU" },
163 1.1 christos { LDP_TLV_RETURNED_MSG, "Returned Message" },
164 1.1 christos { LDP_TLV_COMMON_HELLO, "Common Hello Parameters" },
165 1.1 christos { LDP_TLV_IPV4_TRANSPORT_ADDR, "IPv4 Transport Address" },
166 1.1 christos { LDP_TLV_CONFIG_SEQ_NUMBER, "Configuration Sequence Number" },
167 1.1 christos { LDP_TLV_IPV6_TRANSPORT_ADDR, "IPv6 Transport Address" },
168 1.1 christos { LDP_TLV_COMMON_SESSION, "Common Session Parameters" },
169 1.1 christos { LDP_TLV_ATM_SESSION_PARM, "ATM Session Parameters" },
170 1.1 christos { LDP_TLV_FR_SESSION_PARM, "Frame-Relay Session Parameters" },
171 1.1 christos { LDP_TLV_FT_SESSION, "Fault-Tolerant Session Parameters" },
172 1.1 christos { LDP_TLV_LABEL_REQUEST_MSG_ID, "Label Request Message ID" },
173 1.1 christos { LDP_TLV_MTU, "MTU" },
174 1.1 christos { 0, NULL}
175 1.1 christos };
176 1.1 christos
177 1.1 christos #define LDP_FEC_WILDCARD 0x01
178 1.1 christos #define LDP_FEC_PREFIX 0x02
179 1.1 christos #define LDP_FEC_HOSTADDRESS 0x03
180 1.4 christos /* From RFC 4906; should probably be updated to RFC 4447 (e.g., VC -> PW) */
181 1.1 christos #define LDP_FEC_MARTINI_VC 0x80
182 1.1 christos
183 1.1 christos static const struct tok ldp_fec_values[] = {
184 1.1 christos { LDP_FEC_WILDCARD, "Wildcard" },
185 1.1 christos { LDP_FEC_PREFIX, "Prefix" },
186 1.1 christos { LDP_FEC_HOSTADDRESS, "Host address" },
187 1.1 christos { LDP_FEC_MARTINI_VC, "Martini VC" },
188 1.1 christos { 0, NULL}
189 1.1 christos };
190 1.1 christos
191 1.1 christos #define LDP_FEC_MARTINI_IFPARM_MTU 0x01
192 1.1 christos #define LDP_FEC_MARTINI_IFPARM_DESC 0x03
193 1.1 christos #define LDP_FEC_MARTINI_IFPARM_VCCV 0x0c
194 1.1 christos
195 1.1 christos static const struct tok ldp_fec_martini_ifparm_values[] = {
196 1.1 christos { LDP_FEC_MARTINI_IFPARM_MTU, "MTU" },
197 1.1 christos { LDP_FEC_MARTINI_IFPARM_DESC, "Description" },
198 1.1 christos { LDP_FEC_MARTINI_IFPARM_VCCV, "VCCV" },
199 1.1 christos { 0, NULL}
200 1.1 christos };
201 1.1 christos
202 1.1 christos /* draft-ietf-pwe3-vccv-04.txt */
203 1.1 christos static const struct tok ldp_fec_martini_ifparm_vccv_cc_values[] = {
204 1.1 christos { 0x01, "PWE3 control word" },
205 1.1 christos { 0x02, "MPLS Router Alert Label" },
206 1.1 christos { 0x04, "MPLS inner label TTL = 1" },
207 1.1 christos { 0, NULL}
208 1.1 christos };
209 1.1 christos
210 1.1 christos /* draft-ietf-pwe3-vccv-04.txt */
211 1.1 christos static const struct tok ldp_fec_martini_ifparm_vccv_cv_values[] = {
212 1.1 christos { 0x01, "ICMP Ping" },
213 1.1 christos { 0x02, "LSP Ping" },
214 1.1 christos { 0x04, "BFD" },
215 1.1 christos { 0, NULL}
216 1.1 christos };
217 1.1 christos
218 1.4.8.1 snj static int ldp_pdu_print(netdissect_options *, register const u_char *);
219 1.4.8.1 snj
220 1.4.8.1 snj /*
221 1.1 christos * ldp tlv header
222 1.1 christos *
223 1.1 christos * 0 1 2 3
224 1.1 christos * 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
225 1.1 christos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
226 1.1 christos * |U|F| Type | Length |
227 1.1 christos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
228 1.1 christos * | |
229 1.1 christos * | Value |
230 1.1 christos * ~ ~
231 1.1 christos * | |
232 1.1 christos * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
233 1.1 christos * | |
234 1.1 christos * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
235 1.1 christos */
236 1.1 christos
237 1.4 christos #define TLV_TCHECK(minlen) \
238 1.4.8.1 snj ND_TCHECK2(*tptr, minlen); if (tlv_tlen < minlen) goto badtlv;
239 1.1 christos
240 1.4.8.1 snj static int
241 1.4.8.1 snj ldp_tlv_print(netdissect_options *ndo,
242 1.4.8.1 snj register const u_char *tptr,
243 1.4.8.1 snj u_short msg_tlen)
244 1.4.8.1 snj {
245 1.1 christos struct ldp_tlv_header {
246 1.4.8.1 snj uint8_t type[2];
247 1.4.8.1 snj uint8_t length[2];
248 1.1 christos };
249 1.1 christos
250 1.1 christos const struct ldp_tlv_header *ldp_tlv_header;
251 1.1 christos u_short tlv_type,tlv_len,tlv_tlen,af,ft_flags;
252 1.1 christos u_char fec_type;
253 1.1 christos u_int ui,vc_info_len, vc_info_tlv_type, vc_info_tlv_len,idx;
254 1.1 christos char buf[100];
255 1.1 christos int i;
256 1.1 christos
257 1.4.8.1 snj ldp_tlv_header = (const struct ldp_tlv_header *)tptr;
258 1.4.8.1 snj ND_TCHECK(*ldp_tlv_header);
259 1.1 christos tlv_len=EXTRACT_16BITS(ldp_tlv_header->length);
260 1.4.8.1 snj if (tlv_len + 4 > msg_tlen) {
261 1.4.8.1 snj ND_PRINT((ndo, "\n\t\t TLV contents go past end of message"));
262 1.4.8.1 snj return 0;
263 1.4.8.1 snj }
264 1.1 christos tlv_tlen=tlv_len;
265 1.1 christos tlv_type=LDP_MASK_TLV_TYPE(EXTRACT_16BITS(ldp_tlv_header->type));
266 1.1 christos
267 1.1 christos /* FIXME vendor private / experimental check */
268 1.4.8.1 snj ND_PRINT((ndo, "\n\t %s TLV (0x%04x), length: %u, Flags: [%s and %s forward if unknown]",
269 1.1 christos tok2str(ldp_tlv_values,
270 1.1 christos "Unknown",
271 1.1 christos tlv_type),
272 1.1 christos tlv_type,
273 1.1 christos tlv_len,
274 1.1 christos LDP_MASK_U_BIT(EXTRACT_16BITS(&ldp_tlv_header->type)) ? "continue processing" : "ignore",
275 1.4.8.1 snj LDP_MASK_F_BIT(EXTRACT_16BITS(&ldp_tlv_header->type)) ? "do" : "don't"));
276 1.1 christos
277 1.1 christos tptr+=sizeof(struct ldp_tlv_header);
278 1.1 christos
279 1.1 christos switch(tlv_type) {
280 1.1 christos
281 1.1 christos case LDP_TLV_COMMON_HELLO:
282 1.4 christos TLV_TCHECK(4);
283 1.4.8.1 snj ND_PRINT((ndo, "\n\t Hold Time: %us, Flags: [%s Hello%s]",
284 1.1 christos EXTRACT_16BITS(tptr),
285 1.1 christos (EXTRACT_16BITS(tptr+2)&0x8000) ? "Targeted" : "Link",
286 1.4.8.1 snj (EXTRACT_16BITS(tptr+2)&0x4000) ? ", Request for targeted Hellos" : ""));
287 1.1 christos break;
288 1.1 christos
289 1.1 christos case LDP_TLV_IPV4_TRANSPORT_ADDR:
290 1.4 christos TLV_TCHECK(4);
291 1.4.8.1 snj ND_PRINT((ndo, "\n\t IPv4 Transport Address: %s", ipaddr_string(ndo, tptr)));
292 1.1 christos break;
293 1.1 christos case LDP_TLV_IPV6_TRANSPORT_ADDR:
294 1.4 christos TLV_TCHECK(16);
295 1.4.8.1 snj ND_PRINT((ndo, "\n\t IPv6 Transport Address: %s", ip6addr_string(ndo, tptr)));
296 1.1 christos break;
297 1.1 christos case LDP_TLV_CONFIG_SEQ_NUMBER:
298 1.4 christos TLV_TCHECK(4);
299 1.4.8.1 snj ND_PRINT((ndo, "\n\t Sequence Number: %u", EXTRACT_32BITS(tptr)));
300 1.1 christos break;
301 1.1 christos
302 1.1 christos case LDP_TLV_ADDRESS_LIST:
303 1.4 christos TLV_TCHECK(LDP_TLV_ADDRESS_LIST_AFNUM_LEN);
304 1.1 christos af = EXTRACT_16BITS(tptr);
305 1.1 christos tptr+=LDP_TLV_ADDRESS_LIST_AFNUM_LEN;
306 1.1 christos tlv_tlen -= LDP_TLV_ADDRESS_LIST_AFNUM_LEN;
307 1.4.8.1 snj ND_PRINT((ndo, "\n\t Address Family: %s, addresses",
308 1.4.8.1 snj tok2str(af_values, "Unknown (%u)", af)));
309 1.1 christos switch (af) {
310 1.1 christos case AFNUM_INET:
311 1.1 christos while(tlv_tlen >= sizeof(struct in_addr)) {
312 1.4.8.1 snj ND_TCHECK2(*tptr, sizeof(struct in_addr));
313 1.4.8.1 snj ND_PRINT((ndo, " %s", ipaddr_string(ndo, tptr)));
314 1.1 christos tlv_tlen-=sizeof(struct in_addr);
315 1.4.8.1 snj tptr+=sizeof(struct in_addr);
316 1.1 christos }
317 1.1 christos break;
318 1.1 christos case AFNUM_INET6:
319 1.1 christos while(tlv_tlen >= sizeof(struct in6_addr)) {
320 1.4.8.1 snj ND_TCHECK2(*tptr, sizeof(struct in6_addr));
321 1.4.8.1 snj ND_PRINT((ndo, " %s", ip6addr_string(ndo, tptr)));
322 1.1 christos tlv_tlen-=sizeof(struct in6_addr);
323 1.4.8.1 snj tptr+=sizeof(struct in6_addr);
324 1.1 christos }
325 1.1 christos break;
326 1.1 christos default:
327 1.1 christos /* unknown AF */
328 1.1 christos break;
329 1.1 christos }
330 1.1 christos break;
331 1.1 christos
332 1.1 christos case LDP_TLV_COMMON_SESSION:
333 1.4 christos TLV_TCHECK(8);
334 1.4.8.1 snj ND_PRINT((ndo, "\n\t Version: %u, Keepalive: %us, Flags: [Downstream %s, Loop Detection %s]",
335 1.1 christos EXTRACT_16BITS(tptr), EXTRACT_16BITS(tptr+2),
336 1.1 christos (EXTRACT_16BITS(tptr+6)&0x8000) ? "On Demand" : "Unsolicited",
337 1.1 christos (EXTRACT_16BITS(tptr+6)&0x4000) ? "Enabled" : "Disabled"
338 1.4.8.1 snj ));
339 1.1 christos break;
340 1.1 christos
341 1.1 christos case LDP_TLV_FEC:
342 1.4 christos TLV_TCHECK(1);
343 1.1 christos fec_type = *tptr;
344 1.4.8.1 snj ND_PRINT((ndo, "\n\t %s FEC (0x%02x)",
345 1.1 christos tok2str(ldp_fec_values, "Unknown", fec_type),
346 1.4.8.1 snj fec_type));
347 1.1 christos
348 1.1 christos tptr+=1;
349 1.4 christos tlv_tlen-=1;
350 1.1 christos switch(fec_type) {
351 1.1 christos
352 1.1 christos case LDP_FEC_WILDCARD:
353 1.1 christos break;
354 1.1 christos case LDP_FEC_PREFIX:
355 1.4 christos TLV_TCHECK(2);
356 1.1 christos af = EXTRACT_16BITS(tptr);
357 1.4 christos tptr+=LDP_TLV_ADDRESS_LIST_AFNUM_LEN;
358 1.4 christos tlv_tlen-=LDP_TLV_ADDRESS_LIST_AFNUM_LEN;
359 1.1 christos if (af == AFNUM_INET) {
360 1.4.8.1 snj i=decode_prefix4(ndo, tptr, tlv_tlen, buf, sizeof(buf));
361 1.4 christos if (i == -2)
362 1.4 christos goto trunc;
363 1.4 christos if (i == -3)
364 1.4.8.1 snj ND_PRINT((ndo, ": IPv4 prefix (goes past end of TLV)"));
365 1.4 christos else if (i == -1)
366 1.4.8.1 snj ND_PRINT((ndo, ": IPv4 prefix (invalid length)"));
367 1.4 christos else
368 1.4.8.1 snj ND_PRINT((ndo, ": IPv4 prefix %s", buf));
369 1.1 christos }
370 1.1 christos else if (af == AFNUM_INET6) {
371 1.4.8.1 snj i=decode_prefix6(ndo, tptr, tlv_tlen, buf, sizeof(buf));
372 1.4 christos if (i == -2)
373 1.4 christos goto trunc;
374 1.4 christos if (i == -3)
375 1.4.8.1 snj ND_PRINT((ndo, ": IPv4 prefix (goes past end of TLV)"));
376 1.4 christos else if (i == -1)
377 1.4.8.1 snj ND_PRINT((ndo, ": IPv6 prefix (invalid length)"));
378 1.4 christos else
379 1.4.8.1 snj ND_PRINT((ndo, ": IPv6 prefix %s", buf));
380 1.1 christos }
381 1.4 christos else
382 1.4.8.1 snj ND_PRINT((ndo, ": Address family %u prefix", af));
383 1.1 christos break;
384 1.1 christos case LDP_FEC_HOSTADDRESS:
385 1.1 christos break;
386 1.1 christos case LDP_FEC_MARTINI_VC:
387 1.4 christos /*
388 1.4.8.1 snj * We assume the type was supposed to be one of the MPLS
389 1.4.8.1 snj * Pseudowire Types.
390 1.4.8.1 snj */
391 1.4.8.1 snj TLV_TCHECK(7);
392 1.4.8.1 snj vc_info_len = *(tptr+2);
393 1.4.8.1 snj
394 1.4.8.1 snj /*
395 1.4 christos * According to RFC 4908, the VC info Length field can be zero,
396 1.4 christos * in which case not only are there no interface parameters,
397 1.4 christos * there's no VC ID.
398 1.4 christos */
399 1.4 christos if (vc_info_len == 0) {
400 1.4.8.1 snj ND_PRINT((ndo, ": %s, %scontrol word, group-ID %u, VC-info-length: %u",
401 1.4.8.1 snj tok2str(mpls_pw_types_values, "Unknown", EXTRACT_16BITS(tptr)&0x7fff),
402 1.4 christos EXTRACT_16BITS(tptr)&0x8000 ? "" : "no ",
403 1.4 christos EXTRACT_32BITS(tptr+3),
404 1.4.8.1 snj vc_info_len));
405 1.4 christos break;
406 1.4 christos }
407 1.4 christos
408 1.4 christos /* Make sure we have the VC ID as well */
409 1.4 christos TLV_TCHECK(11);
410 1.4.8.1 snj ND_PRINT((ndo, ": %s, %scontrol word, group-ID %u, VC-ID %u, VC-info-length: %u",
411 1.4.8.1 snj tok2str(mpls_pw_types_values, "Unknown", EXTRACT_16BITS(tptr)&0x7fff),
412 1.1 christos EXTRACT_16BITS(tptr)&0x8000 ? "" : "no ",
413 1.1 christos EXTRACT_32BITS(tptr+3),
414 1.1 christos EXTRACT_32BITS(tptr+7),
415 1.4.8.1 snj vc_info_len));
416 1.4.8.1 snj if (vc_info_len < 4) {
417 1.4.8.1 snj /* minimum 4, for the VC ID */
418 1.4.8.1 snj ND_PRINT((ndo, " (invalid, < 4"));
419 1.4.8.1 snj return(tlv_len+4); /* Type & Length fields not included */
420 1.4.8.1 snj }
421 1.4 christos vc_info_len -= 4; /* subtract out the VC ID, giving the length of the interface parameters */
422 1.1 christos
423 1.4 christos /* Skip past the fixed information and the VC ID */
424 1.1 christos tptr+=11;
425 1.4 christos tlv_tlen-=11;
426 1.4 christos TLV_TCHECK(vc_info_len);
427 1.1 christos
428 1.1 christos while (vc_info_len > 2) {
429 1.1 christos vc_info_tlv_type = *tptr;
430 1.1 christos vc_info_tlv_len = *(tptr+1);
431 1.1 christos if (vc_info_tlv_len < 2)
432 1.1 christos break;
433 1.1 christos if (vc_info_len < vc_info_tlv_len)
434 1.1 christos break;
435 1.1 christos
436 1.4.8.1 snj ND_PRINT((ndo, "\n\t\tInterface Parameter: %s (0x%02x), len %u",
437 1.1 christos tok2str(ldp_fec_martini_ifparm_values,"Unknown",vc_info_tlv_type),
438 1.1 christos vc_info_tlv_type,
439 1.4.8.1 snj vc_info_tlv_len));
440 1.1 christos
441 1.1 christos switch(vc_info_tlv_type) {
442 1.1 christos case LDP_FEC_MARTINI_IFPARM_MTU:
443 1.4.8.1 snj ND_PRINT((ndo, ": %u", EXTRACT_16BITS(tptr+2)));
444 1.1 christos break;
445 1.1 christos
446 1.1 christos case LDP_FEC_MARTINI_IFPARM_DESC:
447 1.4.8.1 snj ND_PRINT((ndo, ": "));
448 1.1 christos for (idx = 2; idx < vc_info_tlv_len; idx++)
449 1.4.8.1 snj safeputchar(ndo, *(tptr + idx));
450 1.1 christos break;
451 1.1 christos
452 1.1 christos case LDP_FEC_MARTINI_IFPARM_VCCV:
453 1.4.8.1 snj ND_PRINT((ndo, "\n\t\t Control Channels (0x%02x) = [%s]",
454 1.1 christos *(tptr+2),
455 1.4.8.1 snj bittok2str(ldp_fec_martini_ifparm_vccv_cc_values, "none", *(tptr+2))));
456 1.4.8.1 snj ND_PRINT((ndo, "\n\t\t CV Types (0x%02x) = [%s]",
457 1.1 christos *(tptr+3),
458 1.4.8.1 snj bittok2str(ldp_fec_martini_ifparm_vccv_cv_values, "none", *(tptr+3))));
459 1.1 christos break;
460 1.1 christos
461 1.1 christos default:
462 1.4.8.1 snj print_unknown_data(ndo, tptr+2, "\n\t\t ", vc_info_tlv_len-2);
463 1.1 christos break;
464 1.1 christos }
465 1.1 christos
466 1.1 christos vc_info_len -= vc_info_tlv_len;
467 1.1 christos tptr += vc_info_tlv_len;
468 1.1 christos }
469 1.1 christos break;
470 1.1 christos }
471 1.1 christos
472 1.1 christos break;
473 1.1 christos
474 1.1 christos case LDP_TLV_GENERIC_LABEL:
475 1.4 christos TLV_TCHECK(4);
476 1.4.8.1 snj ND_PRINT((ndo, "\n\t Label: %u", EXTRACT_32BITS(tptr) & 0xfffff));
477 1.1 christos break;
478 1.1 christos
479 1.1 christos case LDP_TLV_STATUS:
480 1.4 christos TLV_TCHECK(8);
481 1.1 christos ui = EXTRACT_32BITS(tptr);
482 1.1 christos tptr+=4;
483 1.4.8.1 snj ND_PRINT((ndo, "\n\t Status: 0x%02x, Flags: [%s and %s forward]",
484 1.1 christos ui&0x3fffffff,
485 1.1 christos ui&0x80000000 ? "Fatal error" : "Advisory Notification",
486 1.4.8.1 snj ui&0x40000000 ? "do" : "don't"));
487 1.1 christos ui = EXTRACT_32BITS(tptr);
488 1.1 christos tptr+=4;
489 1.1 christos if (ui)
490 1.4.8.1 snj ND_PRINT((ndo, ", causing Message ID: 0x%08x", ui));
491 1.1 christos break;
492 1.1 christos
493 1.1 christos case LDP_TLV_FT_SESSION:
494 1.4 christos TLV_TCHECK(8);
495 1.1 christos ft_flags = EXTRACT_16BITS(tptr);
496 1.4.8.1 snj ND_PRINT((ndo, "\n\t Flags: [%sReconnect, %sSave State, %sAll-Label Protection, %s Checkpoint, %sRe-Learn State]",
497 1.1 christos ft_flags&0x8000 ? "" : "No ",
498 1.1 christos ft_flags&0x8 ? "" : "Don't ",
499 1.1 christos ft_flags&0x4 ? "" : "No ",
500 1.1 christos ft_flags&0x2 ? "Sequence Numbered Label" : "All Labels",
501 1.4.8.1 snj ft_flags&0x1 ? "" : "Don't "));
502 1.1 christos tptr+=4;
503 1.1 christos ui = EXTRACT_32BITS(tptr);
504 1.1 christos if (ui)
505 1.4.8.1 snj ND_PRINT((ndo, ", Reconnect Timeout: %ums", ui));
506 1.1 christos tptr+=4;
507 1.1 christos ui = EXTRACT_32BITS(tptr);
508 1.1 christos if (ui)
509 1.4.8.1 snj ND_PRINT((ndo, ", Recovery Time: %ums", ui));
510 1.1 christos break;
511 1.1 christos
512 1.1 christos case LDP_TLV_MTU:
513 1.4 christos TLV_TCHECK(2);
514 1.4.8.1 snj ND_PRINT((ndo, "\n\t MTU: %u", EXTRACT_16BITS(tptr)));
515 1.1 christos break;
516 1.1 christos
517 1.1 christos
518 1.1 christos /*
519 1.1 christos * FIXME those are the defined TLVs that lack a decoder
520 1.1 christos * you are welcome to contribute code ;-)
521 1.1 christos */
522 1.1 christos
523 1.1 christos case LDP_TLV_HOP_COUNT:
524 1.1 christos case LDP_TLV_PATH_VECTOR:
525 1.1 christos case LDP_TLV_ATM_LABEL:
526 1.1 christos case LDP_TLV_FR_LABEL:
527 1.1 christos case LDP_TLV_EXTD_STATUS:
528 1.1 christos case LDP_TLV_RETURNED_PDU:
529 1.1 christos case LDP_TLV_RETURNED_MSG:
530 1.1 christos case LDP_TLV_ATM_SESSION_PARM:
531 1.1 christos case LDP_TLV_FR_SESSION_PARM:
532 1.1 christos case LDP_TLV_LABEL_REQUEST_MSG_ID:
533 1.1 christos
534 1.1 christos default:
535 1.4.8.1 snj if (ndo->ndo_vflag <= 1)
536 1.4.8.1 snj print_unknown_data(ndo, tptr, "\n\t ", tlv_tlen);
537 1.1 christos break;
538 1.1 christos }
539 1.1 christos return(tlv_len+4); /* Type & Length fields not included */
540 1.4.8.1 snj
541 1.1 christos trunc:
542 1.4.8.1 snj ND_PRINT((ndo, "\n\t\t packet exceeded snapshot"));
543 1.1 christos return 0;
544 1.4 christos
545 1.4 christos badtlv:
546 1.4.8.1 snj ND_PRINT((ndo, "\n\t\t TLV contents go past end of TLV"));
547 1.4 christos return(tlv_len+4); /* Type & Length fields not included */
548 1.1 christos }
549 1.1 christos
550 1.1 christos void
551 1.4.8.1 snj ldp_print(netdissect_options *ndo,
552 1.4.8.1 snj register const u_char *pptr, register u_int len)
553 1.4.8.1 snj {
554 1.1 christos int processed;
555 1.1 christos while (len > (sizeof(struct ldp_common_header) + sizeof(struct ldp_msg_header))) {
556 1.4.8.1 snj processed = ldp_pdu_print(ndo, pptr);
557 1.1 christos if (processed == 0)
558 1.1 christos return;
559 1.1 christos len -= processed;
560 1.1 christos pptr += processed;
561 1.1 christos }
562 1.1 christos }
563 1.1 christos
564 1.4.8.1 snj static int
565 1.4.8.1 snj ldp_pdu_print(netdissect_options *ndo,
566 1.4.8.1 snj register const u_char *pptr)
567 1.4.8.1 snj {
568 1.1 christos const struct ldp_common_header *ldp_com_header;
569 1.1 christos const struct ldp_msg_header *ldp_msg_header;
570 1.1 christos const u_char *tptr,*msg_tptr;
571 1.1 christos u_short tlen;
572 1.1 christos u_short pdu_len,msg_len,msg_type,msg_tlen;
573 1.1 christos int hexdump,processed;
574 1.1 christos
575 1.1 christos ldp_com_header = (const struct ldp_common_header *)pptr;
576 1.4.8.1 snj ND_TCHECK(*ldp_com_header);
577 1.1 christos
578 1.1 christos /*
579 1.1 christos * Sanity checking of the header.
580 1.1 christos */
581 1.1 christos if (EXTRACT_16BITS(&ldp_com_header->version) != LDP_VERSION) {
582 1.4.8.1 snj ND_PRINT((ndo, "%sLDP version %u packet not supported",
583 1.4.8.1 snj (ndo->ndo_vflag < 1) ? "" : "\n\t",
584 1.4.8.1 snj EXTRACT_16BITS(&ldp_com_header->version)));
585 1.1 christos return 0;
586 1.1 christos }
587 1.1 christos
588 1.1 christos pdu_len = EXTRACT_16BITS(&ldp_com_header->pdu_length);
589 1.4.8.1 snj if (pdu_len < sizeof(const struct ldp_common_header)-4) {
590 1.4.8.1 snj /* length too short */
591 1.4.8.1 snj ND_PRINT((ndo, "%sLDP, pdu-length: %u (too short, < %u)",
592 1.4.8.1 snj (ndo->ndo_vflag < 1) ? "" : "\n\t",
593 1.4.8.1 snj pdu_len,
594 1.4.8.1 snj (u_int)(sizeof(const struct ldp_common_header)-4)));
595 1.4.8.1 snj return 0;
596 1.4.8.1 snj }
597 1.4.8.1 snj
598 1.4.8.1 snj /* print the LSR-ID, label-space & length */
599 1.4.8.1 snj ND_PRINT((ndo, "%sLDP, Label-Space-ID: %s:%u, pdu-length: %u",
600 1.4.8.1 snj (ndo->ndo_vflag < 1) ? "" : "\n\t",
601 1.4.8.1 snj ipaddr_string(ndo, &ldp_com_header->lsr_id),
602 1.1 christos EXTRACT_16BITS(&ldp_com_header->label_space),
603 1.4.8.1 snj pdu_len));
604 1.1 christos
605 1.4.8.1 snj /* bail out if non-verbose */
606 1.4.8.1 snj if (ndo->ndo_vflag < 1)
607 1.1 christos return 0;
608 1.1 christos
609 1.1 christos /* ok they seem to want to know everything - lets fully decode it */
610 1.4.8.1 snj tptr = pptr + sizeof(const struct ldp_common_header);
611 1.4.8.1 snj tlen = pdu_len - (sizeof(const struct ldp_common_header)-4); /* Type & Length fields not included */
612 1.1 christos
613 1.1 christos while(tlen>0) {
614 1.1 christos /* did we capture enough for fully decoding the msg header ? */
615 1.4.8.1 snj ND_TCHECK2(*tptr, sizeof(struct ldp_msg_header));
616 1.1 christos
617 1.1 christos ldp_msg_header = (const struct ldp_msg_header *)tptr;
618 1.1 christos msg_len=EXTRACT_16BITS(ldp_msg_header->length);
619 1.1 christos msg_type=LDP_MASK_MSG_TYPE(EXTRACT_16BITS(ldp_msg_header->type));
620 1.1 christos
621 1.4.8.1 snj if (msg_len < sizeof(struct ldp_msg_header)-4) {
622 1.4.8.1 snj /* length too short */
623 1.4.8.1 snj /* FIXME vendor private / experimental check */
624 1.4.8.1 snj ND_PRINT((ndo, "\n\t %s Message (0x%04x), length: %u (too short, < %u)",
625 1.4.8.1 snj tok2str(ldp_msg_values,
626 1.4.8.1 snj "Unknown",
627 1.4.8.1 snj msg_type),
628 1.4.8.1 snj msg_type,
629 1.4.8.1 snj msg_len,
630 1.4.8.1 snj (u_int)(sizeof(struct ldp_msg_header)-4)));
631 1.4.8.1 snj return 0;
632 1.4.8.1 snj }
633 1.4.8.1 snj
634 1.1 christos /* FIXME vendor private / experimental check */
635 1.4.8.1 snj ND_PRINT((ndo, "\n\t %s Message (0x%04x), length: %u, Message ID: 0x%08x, Flags: [%s if unknown]",
636 1.1 christos tok2str(ldp_msg_values,
637 1.1 christos "Unknown",
638 1.1 christos msg_type),
639 1.1 christos msg_type,
640 1.1 christos msg_len,
641 1.1 christos EXTRACT_32BITS(&ldp_msg_header->id),
642 1.4.8.1 snj LDP_MASK_U_BIT(EXTRACT_16BITS(&ldp_msg_header->type)) ? "continue processing" : "ignore"));
643 1.1 christos
644 1.1 christos msg_tptr=tptr+sizeof(struct ldp_msg_header);
645 1.4.8.1 snj msg_tlen=msg_len-(sizeof(struct ldp_msg_header)-4); /* Type & Length fields not included */
646 1.1 christos
647 1.1 christos /* did we capture enough for fully decoding the message ? */
648 1.4.8.1 snj ND_TCHECK2(*tptr, msg_len);
649 1.1 christos hexdump=FALSE;
650 1.1 christos
651 1.1 christos switch(msg_type) {
652 1.4.8.1 snj
653 1.1 christos case LDP_MSG_NOTIF:
654 1.1 christos case LDP_MSG_HELLO:
655 1.1 christos case LDP_MSG_INIT:
656 1.1 christos case LDP_MSG_KEEPALIVE:
657 1.1 christos case LDP_MSG_ADDRESS:
658 1.1 christos case LDP_MSG_LABEL_MAPPING:
659 1.1 christos case LDP_MSG_ADDRESS_WITHDRAW:
660 1.1 christos case LDP_MSG_LABEL_WITHDRAW:
661 1.1 christos while(msg_tlen >= 4) {
662 1.4.8.1 snj processed = ldp_tlv_print(ndo, msg_tptr, msg_tlen);
663 1.1 christos if (processed == 0)
664 1.1 christos break;
665 1.1 christos msg_tlen-=processed;
666 1.1 christos msg_tptr+=processed;
667 1.1 christos }
668 1.1 christos break;
669 1.1 christos
670 1.1 christos /*
671 1.1 christos * FIXME those are the defined messages that lack a decoder
672 1.1 christos * you are welcome to contribute code ;-)
673 1.1 christos */
674 1.1 christos
675 1.1 christos case LDP_MSG_LABEL_REQUEST:
676 1.1 christos case LDP_MSG_LABEL_RELEASE:
677 1.1 christos case LDP_MSG_LABEL_ABORT_REQUEST:
678 1.1 christos
679 1.1 christos default:
680 1.4.8.1 snj if (ndo->ndo_vflag <= 1)
681 1.4.8.1 snj print_unknown_data(ndo, msg_tptr, "\n\t ", msg_tlen);
682 1.1 christos break;
683 1.1 christos }
684 1.1 christos /* do we want to see an additionally hexdump ? */
685 1.4.8.1 snj if (ndo->ndo_vflag > 1 || hexdump==TRUE)
686 1.4.8.1 snj print_unknown_data(ndo, tptr+sizeof(struct ldp_msg_header), "\n\t ",
687 1.1 christos msg_len);
688 1.1 christos
689 1.1 christos tptr += msg_len+4;
690 1.1 christos tlen -= msg_len+4;
691 1.1 christos }
692 1.1 christos return pdu_len+4;
693 1.1 christos trunc:
694 1.4.8.1 snj ND_PRINT((ndo, "\n\t\t packet exceeded snapshot"));
695 1.1 christos return 0;
696 1.1 christos }
697 1.1 christos
698 1.4.8.1 snj /*
699 1.4.8.1 snj * Local Variables:
700 1.4.8.1 snj * c-style: whitesmith
701 1.4.8.1 snj * c-basic-offset: 8
702 1.4.8.1 snj * End:
703 1.4.8.1 snj */
704