1/*
2 * Copyright (c) 1998-2007 The TCPDUMP project
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that: (1) source code
6 * distributions retain the above copyright notice and this paragraph
7 * in its entirety, and (2) distributions including binary code include
8 * the above copyright notice and this paragraph in its entirety in
9 * the documentation or other materials provided with the distribution.
10 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
11 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
12 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13 * FOR A PARTICULAR PURPOSE.
14 *
15 * UNIDIRECTIONAL LINK DETECTION (UDLD) as per
16 * http://www.ietf.org/internet-drafts/draft-foschiano-udld-02.txt
17 *
18 * Original code by Carles Kishimoto <carles.kishimoto@gmail.com>
19 */
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 <string.h>
29
30#include "interface.h"
31#include "addrtoname.h"
32#include "extract.h"
33#include "nlpid.h"
34
35#define UDLD_HEADER_LEN			4
36#define UDLD_DEVICE_ID_TLV		0x0001
37#define UDLD_PORT_ID_TLV		0x0002
38#define UDLD_ECHO_TLV			0x0003
39#define UDLD_MESSAGE_INTERVAL_TLV	0x0004
40#define UDLD_TIMEOUT_INTERVAL_TLV	0x0005
41#define UDLD_DEVICE_NAME_TLV		0x0006
42#define UDLD_SEQ_NUMBER_TLV		0x0007
43
44static const struct tok udld_tlv_values[] = {
45    { UDLD_DEVICE_ID_TLV, "Device-ID TLV"},
46    { UDLD_PORT_ID_TLV, "Port-ID TLV"},
47    { UDLD_ECHO_TLV, "Echo TLV"},
48    { UDLD_MESSAGE_INTERVAL_TLV, "Message Interval TLV"},
49    { UDLD_TIMEOUT_INTERVAL_TLV, "Timeout Interval TLV"},
50    { UDLD_DEVICE_NAME_TLV, "Device Name TLV"},
51    { UDLD_SEQ_NUMBER_TLV,"Sequence Number TLV"},
52    { 0, NULL}
53};
54
55static const struct tok udld_code_values[] = {
56    { 0x00, "Reserved"},
57    { 0x01, "Probe message"},
58    { 0x02, "Echo message"},
59    { 0x03, "Flush message"},
60    { 0, NULL}
61};
62
63static const struct tok udld_flags_values[] = {
64    { 0x00, "RT"},
65    { 0x01, "RSY"},
66    { 0, NULL}
67};
68
69/*
70 *
71 * 0                   1                   2                   3
72 * 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
73 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
74 * | Ver | Opcode  |     Flags     |           Checksum            |
75 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
76 * |               List of TLVs (variable length list)             |
77 * |                              ...                              |
78 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
79 *
80 */
81
82#define	UDLD_EXTRACT_VERSION(x) (((x)&0xe0)>>5)
83#define	UDLD_EXTRACT_OPCODE(x) ((x)&0x1f)
84
85void
86udld_print (const u_char *pptr, u_int length)
87{
88    int code, type, len;
89    const u_char *tptr;
90
91    if (length < UDLD_HEADER_LEN)
92        goto trunc;
93
94    tptr = pptr;
95
96    if (!TTEST2(*tptr, UDLD_HEADER_LEN))
97	goto trunc;
98
99    code = UDLD_EXTRACT_OPCODE(*tptr);
100
101    printf("UDLDv%u, Code %s (%x), Flags [%s] (0x%02x), length %u",
102           UDLD_EXTRACT_VERSION(*tptr),
103           tok2str(udld_code_values, "Reserved", code),
104           code,
105           bittok2str(udld_flags_values, "none", *(tptr+1)),
106           *(tptr+1),
107           length);
108
109    /*
110     * In non-verbose mode, just print version and opcode type
111     */
112    if (vflag < 1) {
113	return;
114    }
115
116    printf("\n\tChecksum 0x%04x (unverified)", EXTRACT_16BITS(tptr+2));
117
118    tptr += UDLD_HEADER_LEN;
119
120    while (tptr < (pptr+length)) {
121
122        if (!TTEST2(*tptr, 4))
123            goto trunc;
124
125	type = EXTRACT_16BITS(tptr);
126        len  = EXTRACT_16BITS(tptr+2);
127        len -= 4;
128        tptr += 4;
129
130        /* infinite loop check */
131        if (type == 0 || len == 0) {
132            return;
133        }
134
135        printf("\n\t%s (0x%04x) TLV, length %u",
136               tok2str(udld_tlv_values, "Unknown", type),
137               type, len);
138
139        switch (type) {
140        case UDLD_DEVICE_ID_TLV:
141        case UDLD_PORT_ID_TLV:
142        case UDLD_ECHO_TLV:
143        case UDLD_DEVICE_NAME_TLV:
144            printf(", %s", tptr);
145            break;
146
147        case UDLD_MESSAGE_INTERVAL_TLV:
148        case UDLD_TIMEOUT_INTERVAL_TLV:
149            printf(", %us", (*tptr));
150            break;
151
152        case UDLD_SEQ_NUMBER_TLV:
153            printf(", %u", EXTRACT_32BITS(tptr));
154            break;
155
156        default:
157            break;
158        }
159        tptr += len;
160    }
161
162    return;
163
164 trunc:
165    printf("[|udld]");
166}
167
168/*
169 * Local Variables:
170 * c-style: whitesmith
171 * c-basic-offset: 4
172 * End:
173 */
174