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