]> The Tcpdump Group git mirrors - tcpdump/blob - print-lmp.c
c7ee6dd79b58256295edba20c61515374ad0c532
[tcpdump] / print-lmp.c
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 #ifndef lint
17 static const char rcsid[] _U_ =
18 "@(#) $Header: /tcpdump/master/tcpdump/print-lmp.c,v 1.1 2004-04-19 21:17:13 hannes Exp $";
19 #endif
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <tcpdump-stdinc.h>
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "interface.h"
32 #include "extract.h"
33 #include "addrtoname.h"
34
35 /*
36 * LMP common header
37 *
38 * 0 1 2 3
39 * 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
40 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41 * | Vers | (Reserved) | Flags | Msg Type |
42 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43 * | LMP Length | (Reserved) |
44 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45 */
46
47 struct lmp_common_header {
48 u_int8_t version_res[2];
49 u_int8_t flags;
50 u_int8_t msg_type;
51 u_int8_t length[2];
52 u_int8_t reserved[2];
53 };
54
55 #define LMP_VERSION 1
56 #define LMP_EXTRACT_VERSION(x) (((x)&0xf0)>>4)
57
58 static const struct tok lmp_header_flag_values[] = {
59 { 0x00, "Control Channel Down"},
60 { 0x02, "LMP restart"},
61 { 0, NULL}
62 };
63
64 #define LMP_MSGTYPE_CONFIG 1
65 #define LMP_MSGTYPE_CONFIG_ACK 2
66 #define LMP_MSGTYPE_CONFIG_NACK 3
67 #define LMP_MSGTYPE_HELLO 4
68 #define LMP_MSGTYPE_VERIFY_BEGIN 5
69 #define LMP_MSGTYPE_VERIFY_BEGIN_ACK 6
70 #define LMP_MSGTYPE_VERIFY_BEGIN_NACK 7
71 #define LMP_MSGTYPE_VERIFY_END 8
72 #define LMP_MSGTYPE_VERIFY_END_ACK 9
73 #define LMP_MSGTYPE_TEST 10
74 #define LMP_MSGTYPE_TEST_STATUS_SUCCESS 11
75 #define LMP_MSGTYPE_TEST_STATUS_FAILURE 12
76 #define LMP_MSGTYPE_TEST_STATUS_ACK 13
77 #define LMP_MSGTYPE_LINK_SUMMARY 14
78 #define LMP_MSGTYPE_LINK_SUMMARY_ACK 15
79 #define LMP_MSGTYPE_LINK_SUMMARY_NACK 16
80 #define LMP_MSGTYPE_CHANNEL_STATUS 17
81 #define LMP_MSGTYPE_CHANNEL_STATUS_ACK 18
82 #define LMP_MSGTYPE_CHANNEL_STATUS_REQ 19
83 #define LMP_MSGTYPE_CHANNEL_STATUS_RESP 20
84
85 static const struct tok lmp_msg_type_values[] = {
86 { LMP_MSGTYPE_CONFIG, "Config"},
87 { LMP_MSGTYPE_CONFIG_ACK, "Config ACK"},
88 { LMP_MSGTYPE_CONFIG_NACK, "Config NACK"},
89 { LMP_MSGTYPE_HELLO, "Hello"},
90 { LMP_MSGTYPE_VERIFY_BEGIN, "Begin Verify"},
91 { LMP_MSGTYPE_VERIFY_BEGIN_ACK, "Begin Verify ACK"},
92 { LMP_MSGTYPE_VERIFY_BEGIN_NACK, "Begin Verify NACK"},
93 { LMP_MSGTYPE_VERIFY_END, "End Verify"},
94 { LMP_MSGTYPE_VERIFY_END_ACK, "End Verify ACK"},
95 { LMP_MSGTYPE_TEST, "Test"},
96 { LMP_MSGTYPE_TEST_STATUS_SUCCESS, "Test Status Success"},
97 { LMP_MSGTYPE_TEST_STATUS_FAILURE, "Test Status Failure"},
98 { LMP_MSGTYPE_TEST_STATUS_ACK, "Test Status ACK"},
99 { LMP_MSGTYPE_LINK_SUMMARY, "Link Summary"},
100 { LMP_MSGTYPE_LINK_SUMMARY_ACK, "Link Summary ACK"},
101 { LMP_MSGTYPE_LINK_SUMMARY_NACK, "Link Summary NACK"},
102 { LMP_MSGTYPE_CHANNEL_STATUS, "Channel Status"},
103 { LMP_MSGTYPE_CHANNEL_STATUS_ACK, "Channel Status ACK"},
104 { LMP_MSGTYPE_CHANNEL_STATUS_REQ, "Channel Status Request"},
105 { LMP_MSGTYPE_CHANNEL_STATUS_RESP, "Channel Status Response"},
106 { 0, NULL}
107 };
108
109 /*
110 * LMP object header
111 *
112 * 0 1 2 3
113 * 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
114 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
115 * |N| C-Type | Class | Length |
116 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
117 * | |
118 * // (object contents) //
119 * | |
120 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
121 */
122
123 struct lmp_object_header {
124 u_int8_t ctype;
125 u_int8_t class_num;
126 u_int8_t length[2];
127 };
128
129 #define LMP_OBJ_CC_ID 1
130 #define LMP_OBJ_NODE_ID 2
131 #define LMP_OBJ_LINK_ID 3
132 #define LMP_OBJ_INTERFACE_ID 4
133 #define LMP_OBJ_MESSAGE_ID 5
134 #define LMP_OBJ_CONFIG 6
135 #define LMP_OBJ_HELLO 7
136 #define LMP_OBJ_VERIFY_BEGIN 8
137 #define LMP_OBJ_VERIFY_BEGIN_ACK 9
138 #define LMP_OBJ_VERIFY_ID 10
139 #define LMP_OBJ_TE_LINK 11
140 #define LMP_OBJ_DATA_LINK 12
141 #define LMP_OBJ_CHANNEL_STATUS 13
142 #define LMP_OBJ_CHANNEL_STATUS_REQ 14
143 #define LMP_OBJ_ERROR_CODE 15
144
145 static const struct tok lmp_obj_values[] = {
146 { LMP_OBJ_CC_ID, "Control Channel ID" },
147 { LMP_OBJ_NODE_ID, "Node ID" },
148 { LMP_OBJ_LINK_ID, "Link ID" },
149 { LMP_OBJ_INTERFACE_ID, "Interface ID" },
150 { LMP_OBJ_MESSAGE_ID, "Message ID" },
151 { LMP_OBJ_CONFIG, "Configuration" },
152 { LMP_OBJ_HELLO, "Hello" },
153 { LMP_OBJ_VERIFY_BEGIN, "Verify Begin" },
154 { LMP_OBJ_VERIFY_BEGIN_ACK, "Verify Begin ACK" },
155 { LMP_OBJ_VERIFY_ID, "Verify ID" },
156 { LMP_OBJ_TE_LINK, "TE Link" },
157 { LMP_OBJ_DATA_LINK, "Data Link" },
158 { LMP_OBJ_CHANNEL_STATUS, "Channel Status" },
159 { LMP_OBJ_CHANNEL_STATUS_REQ, "Channel Status Request" },
160 { LMP_OBJ_ERROR_CODE, "Error Code" },
161 { 0, NULL}
162 };
163
164 #define LMP_CTYPE_IPV4 1
165 #define LMP_CTYPE_IPV6 2
166
167 #define LMP_CTYPE_LOC 1
168 #define LMP_CTYPE_RMT 2
169 #define LMP_CTYPE_UNMD 3
170
171 #define LMP_CTYPE_IPV4_LOC 1
172 #define LMP_CTYPE_IPV4_RMT 2
173 #define LMP_CTYPE_IPV6_LOC 3
174 #define LMP_CTYPE_IPV6_RMT 4
175 #define LMP_CTYPE_UNMD_LOC 5
176 #define LMP_CTYPE_UNMD_RMT 6
177
178 #define LMP_CTYPE_1 1
179 #define LMP_CTYPE_2 2
180
181 #define FALSE 0
182 #define TRUE 1
183
184 /*
185 * the ctypes are not globally unique so for
186 * translating it to strings we build a table based
187 * on objects offsetted by the ctype
188 */
189
190 static const struct tok lmp_ctype_values[] = {
191 { 256*LMP_OBJ_CC_ID+LMP_CTYPE_LOC, "Local" },
192 { 256*LMP_OBJ_CC_ID+LMP_CTYPE_RMT, "Remote" },
193 { 256*LMP_OBJ_NODE_ID+LMP_CTYPE_LOC, "Local" },
194 { 256*LMP_OBJ_NODE_ID+LMP_CTYPE_RMT, "Remote" },
195 { 256*LMP_OBJ_LINK_ID+LMP_CTYPE_IPV4_LOC, "IPv4 Local" },
196 { 256*LMP_OBJ_LINK_ID+LMP_CTYPE_IPV4_RMT, "IPv4 Remote" },
197 { 256*LMP_OBJ_LINK_ID+LMP_CTYPE_IPV6_LOC, "IPv6 Local" },
198 { 256*LMP_OBJ_LINK_ID+LMP_CTYPE_IPV6_RMT, "IPv6 Remote" },
199 { 256*LMP_OBJ_LINK_ID+LMP_CTYPE_UNMD_LOC, "Unnumbered Local" },
200 { 256*LMP_OBJ_LINK_ID+LMP_CTYPE_UNMD_RMT, "Unnumbered Remote" },
201 { 256*LMP_OBJ_INTERFACE_ID+LMP_CTYPE_IPV4_LOC, "IPv4 Local" },
202 { 256*LMP_OBJ_INTERFACE_ID+LMP_CTYPE_IPV4_RMT, "IPv4 Remote" },
203 { 256*LMP_OBJ_INTERFACE_ID+LMP_CTYPE_IPV6_LOC, "IPv6 Local" },
204 { 256*LMP_OBJ_INTERFACE_ID+LMP_CTYPE_IPV6_RMT, "IPv6 Remote" },
205 { 256*LMP_OBJ_INTERFACE_ID+LMP_CTYPE_UNMD_LOC, "Unnumbered Local" },
206 { 256*LMP_OBJ_INTERFACE_ID+LMP_CTYPE_UNMD_RMT, "Unnumbered Remote" },
207 { 256*LMP_OBJ_MESSAGE_ID+LMP_CTYPE_1, "1" },
208 { 256*LMP_OBJ_MESSAGE_ID+LMP_CTYPE_2, "2" },
209 { 256*LMP_OBJ_CONFIG+LMP_CTYPE_1, "1" },
210 { 256*LMP_OBJ_HELLO+LMP_CTYPE_1, "1" },
211 { 256*LMP_OBJ_VERIFY_BEGIN+LMP_CTYPE_1, "1" },
212 { 256*LMP_OBJ_VERIFY_BEGIN_ACK+LMP_CTYPE_1, "1" },
213 { 256*LMP_OBJ_VERIFY_ID+LMP_CTYPE_1, "1" },
214 { 256*LMP_OBJ_TE_LINK+LMP_CTYPE_IPV4, "IPv4" },
215 { 256*LMP_OBJ_TE_LINK+LMP_CTYPE_IPV6, "IPv6" },
216 { 256*LMP_OBJ_TE_LINK+LMP_CTYPE_UNMD, "Unnumbered" },
217 { 256*LMP_OBJ_DATA_LINK+LMP_CTYPE_IPV4, "IPv4" },
218 { 256*LMP_OBJ_DATA_LINK+LMP_CTYPE_IPV6, "IPv6" },
219 { 256*LMP_OBJ_DATA_LINK+LMP_CTYPE_UNMD, "Unnumbered" },
220 { 256*LMP_OBJ_CHANNEL_STATUS+LMP_CTYPE_IPV4, "IPv4" },
221 { 256*LMP_OBJ_CHANNEL_STATUS+LMP_CTYPE_IPV6, "IPv6" },
222 { 256*LMP_OBJ_CHANNEL_STATUS+LMP_CTYPE_UNMD, "Unnumbered" },
223 { 256*LMP_OBJ_CHANNEL_STATUS_REQ+LMP_CTYPE_IPV4, "IPv4" },
224 { 256*LMP_OBJ_CHANNEL_STATUS_REQ+LMP_CTYPE_IPV6, "IPv6" },
225 { 256*LMP_OBJ_CHANNEL_STATUS_REQ+LMP_CTYPE_UNMD, "Unnumbered" },
226 { 256*LMP_OBJ_ERROR_CODE+LMP_CTYPE_1, "1" },
227 { 256*LMP_OBJ_ERROR_CODE+LMP_CTYPE_2, "2" },
228 { 0, NULL}
229 };
230
231 void
232 lmp_print(register const u_char *pptr, register u_int len) {
233
234 const struct lmp_common_header *lmp_com_header;
235 const struct lmp_object_header *lmp_obj_header;
236 const u_char *tptr,*obj_tptr;
237 u_short tlen,lmp_obj_len,lmp_obj_ctype,obj_tlen;
238 int hexdump;
239
240 tptr=pptr;
241 lmp_com_header = (const struct lmp_common_header *)pptr;
242 TCHECK(*lmp_com_header);
243
244 /*
245 * Sanity checking of the header.
246 */
247 if (LMP_EXTRACT_VERSION(lmp_com_header->version_res[0]) != LMP_VERSION) {
248 printf("LMP version %u packet not supported",
249 LMP_EXTRACT_VERSION(lmp_com_header->version_res[0]));
250 return;
251 }
252
253 /* in non-verbose mode just lets print the basic Message Type*/
254 if (vflag < 1) {
255 printf("LMPv%u %s Message, length: %u",
256 LMP_EXTRACT_VERSION(lmp_com_header->version_res[0]),
257 tok2str(lmp_msg_type_values, "unknown (%u)",lmp_com_header->msg_type),
258 len);
259 return;
260 }
261
262 /* ok they seem to want to know everything - lets fully decode it */
263
264 tlen=EXTRACT_16BITS(lmp_com_header->length);
265
266 printf("\n\tLMPv%u, msg-type: %s, Flags: [%s], length: %u",
267 LMP_EXTRACT_VERSION(lmp_com_header->version_res[0]),
268 tok2str(lmp_msg_type_values, "unknown, type: %u",lmp_com_header->msg_type),
269 bittok2str(lmp_header_flag_values,"none",lmp_com_header->flags),
270 tlen);
271
272 tptr+=sizeof(const struct lmp_common_header);
273 tlen-=sizeof(const struct lmp_common_header);
274
275 while(tlen>0) {
276 /* did we capture enough for fully decoding the object header ? */
277 if (!TTEST2(*tptr, sizeof(struct lmp_object_header)))
278 goto trunc;
279
280 lmp_obj_header = (const struct lmp_object_header *)tptr;
281 lmp_obj_len=EXTRACT_16BITS(lmp_obj_header->length);
282 lmp_obj_ctype=(lmp_obj_header->ctype)&0x7f;
283
284 if(lmp_obj_len % 4 || lmp_obj_len < 4)
285 return;
286
287 printf("\n\t %s Object (%u), Class-Type: %s (%u) Flags: [%snegotiable], length: %u",
288 tok2str(lmp_obj_values,
289 "Unknown",
290 lmp_obj_header->class_num),
291 lmp_obj_header->class_num,
292 tok2str(lmp_ctype_values,
293 "Unknown",
294 ((lmp_obj_header->class_num)<<8)+lmp_obj_ctype),
295 lmp_obj_ctype,
296 (lmp_obj_header->ctype)&0x80 ? "" : "non-",
297 lmp_obj_len);
298
299 obj_tptr=tptr+sizeof(struct lmp_object_header);
300 obj_tlen=lmp_obj_len-sizeof(struct lmp_object_header);
301
302 /* did we capture enough for fully decoding the object ? */
303 if (!TTEST2(*tptr, lmp_obj_len))
304 goto trunc;
305 hexdump=FALSE;
306
307 switch(lmp_obj_header->class_num) {
308
309 case LMP_OBJ_CC_ID:
310 switch(lmp_obj_ctype) {
311 case LMP_CTYPE_LOC:
312 case LMP_CTYPE_RMT:
313 printf("\n\t Control Channel ID: %u (0x%08x)",
314 EXTRACT_32BITS(obj_tptr),
315 EXTRACT_32BITS(obj_tptr));
316 break;
317
318 default:
319 hexdump=TRUE;
320 }
321 break;
322
323 case LMP_OBJ_LINK_ID:
324 case LMP_OBJ_INTERFACE_ID:
325 switch(lmp_obj_ctype) {
326 case LMP_CTYPE_IPV4_LOC:
327 case LMP_CTYPE_IPV4_RMT:
328 printf("\n\t IPv4 Link ID: %s (0x%08x)",
329 ipaddr_string(obj_tptr),
330 EXTRACT_32BITS(obj_tptr));
331 break;
332 #ifdef INET6
333 case LMP_CTYPE_IPV6_LOC:
334 case LMP_CTYPE_IPV6_RMT:
335 printf("\n\t IPv6 Link ID: %s (0x%08x)",
336 ip6addr_string(obj_tptr),
337 EXTRACT_32BITS(obj_tptr));
338 break;
339 #endif
340 case LMP_CTYPE_UNMD_LOC:
341 case LMP_CTYPE_UNMD_RMT:
342 printf("\n\t Link ID: %u (0x%08x)",
343 EXTRACT_32BITS(obj_tptr),
344 EXTRACT_32BITS(obj_tptr));
345 break;
346 default:
347 hexdump=TRUE;
348 }
349 break;
350
351 case LMP_OBJ_MESSAGE_ID:
352 switch(lmp_obj_ctype) {
353 case LMP_CTYPE_1:
354 printf("\n\t Message ID: %u (0x%08x)",
355 EXTRACT_32BITS(obj_tptr),
356 EXTRACT_32BITS(obj_tptr));
357 break;
358 case LMP_CTYPE_2:
359 printf("\n\t Message ID Ack: %u (0x%08x)",
360 EXTRACT_32BITS(obj_tptr),
361 EXTRACT_32BITS(obj_tptr));
362 break;
363 default:
364 hexdump=TRUE;
365 }
366 break;
367
368 case LMP_OBJ_NODE_ID:
369 switch(lmp_obj_ctype) {
370 case LMP_CTYPE_LOC:
371 case LMP_CTYPE_RMT:
372 printf("\n\t Node ID: %s (0x%08x)",
373 ipaddr_string(obj_tptr),
374 EXTRACT_32BITS(obj_tptr));
375 break;
376
377 default:
378 hexdump=TRUE;
379 }
380 break;
381
382 /*
383 * FIXME those are the defined objects that lack a decoder
384 * you are welcome to contribute code ;-)
385 */
386
387 case LMP_OBJ_CONFIG:
388 case LMP_OBJ_HELLO:
389 case LMP_OBJ_VERIFY_BEGIN:
390 case LMP_OBJ_VERIFY_BEGIN_ACK:
391 case LMP_OBJ_VERIFY_ID:
392 case LMP_OBJ_TE_LINK:
393 case LMP_OBJ_DATA_LINK:
394 case LMP_OBJ_CHANNEL_STATUS:
395 case LMP_OBJ_CHANNEL_STATUS_REQ:
396 case LMP_OBJ_ERROR_CODE:
397
398 default:
399 if (vflag <= 1)
400 print_unknown_data(obj_tptr,"\n\t ",obj_tlen);
401 break;
402 }
403 /* do we want to see an additionally hexdump ? */
404 if (vflag > 1 || hexdump==TRUE)
405 print_unknown_data(tptr+sizeof(sizeof(struct lmp_object_header)),"\n\t ",
406 lmp_obj_len-sizeof(struct lmp_object_header));
407
408 tptr+=lmp_obj_len;
409 tlen-=lmp_obj_len;
410 }
411 return;
412 trunc:
413 printf("\n\t\t packet exceeded snapshot");
414 }