]>
Commit | Line | Data |
---|---|---|
dedb1eb0 VB |
1 | /* -*- mode: c; c-file-style: "openbsd" -*- */ |
2 | /* | |
3 | * Copyright (c) 2015 Vincent Bernat <bernat@luffy.cx> | |
4 | * | |
5 | * Permission to use, copy, modify, and/or distribute this software for any | |
6 | * purpose with or without fee is hereby granted, provided that the above | |
7 | * copyright notice and this permission notice appear in all copies. | |
8 | * | |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
16 | */ | |
17 | ||
18 | #include <stdlib.h> | |
f681619c | 19 | #include <unistd.h> |
dedb1eb0 VB |
20 | #include <inttypes.h> |
21 | #include <sys/types.h> | |
22 | #include <sys/stat.h> | |
23 | #include <fcntl.h> | |
24 | #include <arpa/inet.h> | |
25 | #include "common.h" | |
26 | ||
27 | #define BUFSIZE 2000 | |
28 | ||
29 | char filenameprefix[] = "decode"; | |
30 | ||
31 | static void | |
32 | usage(void) | |
33 | { | |
34 | fprintf(stderr, "Usage: %s PCAP\n", "decode"); | |
35 | fprintf(stderr, "Version: %s\n", PACKAGE_STRING); | |
36 | ||
37 | fprintf(stderr, "\n"); | |
38 | ||
39 | fprintf(stderr, "Decode content of PCAP files and display a summary\n"); | |
40 | fprintf(stderr, "on standard output. Only the first packet is decoded.\n"); | |
41 | exit(1); | |
42 | } | |
43 | ||
069acc41 VB |
44 | char* |
45 | tohex(char *str, size_t len) | |
46 | { | |
47 | static char *hex = NULL; | |
48 | free(hex); hex = NULL; | |
49 | if ((hex = malloc(len * 3 + 1)) == NULL) return NULL; | |
50 | for (size_t i = 0; i < len; i++) | |
51 | snprintf(hex + 3*i, 4, "%02X ", (unsigned char)str[i]); | |
52 | return hex; | |
53 | } | |
54 | ||
dedb1eb0 VB |
55 | /* We need an assert macro which doesn't abort */ |
56 | #define assert(x) while (!(x)) { \ | |
57 | fprintf(stderr, "%s:%d: %s: Assertion `%s' failed.\n", \ | |
58 | __FILE__, __LINE__, __func__, #x); \ | |
59 | exit(5); \ | |
60 | } | |
61 | ||
62 | int | |
63 | main(int argc, char **argv) | |
64 | { | |
65 | if (argc != 2 || | |
66 | !strcmp(argv[1], "-h") || | |
67 | !strcmp(argv[1], "--help")) | |
68 | usage(); | |
69 | ||
70 | int fd = open(argv[1], O_RDONLY); | |
71 | assert(fd != -1); | |
72 | ||
73 | char buf[BUFSIZE]; | |
74 | ssize_t len = read(fd, buf, BUFSIZE); | |
75 | assert(len != -1); | |
76 | ||
77 | struct pcap_hdr hdr; | |
78 | assert(len >= sizeof(hdr)); | |
79 | memcpy(&hdr, buf, sizeof(hdr)); | |
80 | assert(hdr.magic_number == 0xa1b2c3d4); /* Assume the same byte order as us */ | |
81 | assert(hdr.version_major == 2); | |
82 | assert(hdr.version_minor == 4); | |
83 | assert(hdr.thiszone == 0); | |
84 | /* Don't care about other flags */ | |
85 | ||
86 | struct pcaprec_hdr rechdr; | |
87 | assert(len >= sizeof(hdr) + sizeof(rechdr)); | |
88 | memcpy(&rechdr, buf + sizeof(hdr), sizeof(rechdr)); | |
89 | assert(len >= sizeof(hdr) + sizeof(rechdr) + rechdr.incl_len); | |
90 | ||
91 | /* For decoding, we only need a very basic hardware */ | |
92 | struct lldpd_hardware hardware; | |
93 | memset(&hardware, 0, sizeof(struct lldpd_hardware)); | |
94 | hardware.h_mtu = 1500; | |
95 | strlcpy(hardware.h_ifname, "test", sizeof(hardware.h_ifname)); | |
96 | ||
97 | char *frame = buf + sizeof(hdr) + sizeof(rechdr); | |
98 | struct lldpd_chassis *nchassis = NULL; | |
99 | struct lldpd_port *nport = NULL; | |
100 | int decoded = 0; | |
101 | if (lldp_decode(NULL, frame, rechdr.incl_len, &hardware, &nchassis, &nport) == -1) { | |
102 | fprintf(stderr, "Not decoded as a LLDP frame\n"); | |
103 | } else { | |
104 | fprintf(stderr, "Decoded as a LLDP frame\n"); | |
105 | decoded = 1; | |
106 | } | |
107 | #if defined ENABLE_CDP || defined ENABLE_FDP | |
108 | if (cdp_decode(NULL, frame, rechdr.incl_len, &hardware, &nchassis, &nport) == -1) { | |
109 | fprintf(stderr, "Not decoded as a CDP frame\n"); | |
110 | } else { | |
111 | fprintf(stderr, "Decoded as a CDP frame\n"); | |
112 | decoded = 1; | |
113 | } | |
114 | #endif | |
115 | #ifdef ENABLE_SONMP | |
116 | if (sonmp_decode(NULL, frame, rechdr.incl_len, &hardware, &nchassis, &nport) == -1) { | |
117 | fprintf(stderr, "Not decoded as a SONMP frame\n"); | |
118 | } else { | |
119 | fprintf(stderr, "Decoded as a SONMP frame\n"); | |
120 | decoded = 1; | |
121 | } | |
122 | #endif | |
123 | #ifdef ENABLE_EDP | |
124 | if (edp_decode(NULL, frame, rechdr.incl_len, &hardware, &nchassis, &nport) == -1) { | |
125 | fprintf(stderr, "Not decoded as a EDP frame\n"); | |
126 | } else { | |
127 | fprintf(stderr, "Decoded as a EDP frame\n"); | |
128 | decoded = 1; | |
129 | } | |
130 | #endif | |
131 | if (!decoded) exit(1); | |
132 | ||
133 | printf("Chassis:\n"); | |
134 | printf(" Index: %" PRIu16 "\n", nchassis->c_index); | |
135 | printf(" Protocol: %" PRIu8 "\n", nchassis->c_protocol); | |
136 | printf(" ID subtype: %" PRIu8 "\n", nchassis->c_id_subtype); | |
137 | printf(" ID: %s\n", tohex(nchassis->c_id, nchassis->c_id_len)); | |
138 | printf(" Name: %s\n", nchassis->c_name?nchassis->c_name:"(null)"); | |
139 | printf(" Description: %s\n", nchassis->c_descr?nchassis->c_descr:"(null)"); | |
140 | printf(" Cap available: %" PRIu16 "\n", nchassis->c_cap_available); | |
141 | printf(" Cap enabled: %" PRIu16 "\n", nchassis->c_cap_enabled); | |
142 | printf(" TTL: %" PRIu16 "\n", nchassis->c_ttl); | |
143 | struct lldpd_mgmt *mgmt; | |
144 | TAILQ_FOREACH(mgmt, &nchassis->c_mgmt, m_entries) { | |
145 | char ipaddress[INET6_ADDRSTRLEN + 1]; | |
146 | int af; size_t alen; | |
147 | switch (mgmt->m_family) { | |
148 | case LLDPD_AF_IPV4: | |
149 | alen = INET_ADDRSTRLEN + 1; | |
150 | af = AF_INET; | |
151 | break; | |
152 | case LLDPD_AF_IPV6: | |
153 | alen = INET6_ADDRSTRLEN + 1; | |
154 | af = AF_INET6; | |
155 | break; | |
156 | default: | |
157 | len = 0; | |
158 | } | |
159 | if (len == 0) continue; | |
160 | if (inet_ntop(af, &mgmt->m_addr, ipaddress, alen) == NULL) | |
161 | break; | |
162 | printf(" mgmt: %s\n", ipaddress); | |
163 | } | |
164 | #ifdef ENABLE_LLDPMED | |
165 | printf(" MED cap: %" PRIu16 "\n", nchassis->c_med_cap_available); | |
166 | printf(" MED type: %" PRIu8 "\n", nchassis->c_med_type); | |
167 | printf(" MED HW: %s\n", nchassis->c_med_hw?nchassis->c_med_hw:"(null)"); | |
168 | printf(" MED FW: %s\n", nchassis->c_med_fw?nchassis->c_med_fw:"(null)"); | |
169 | printf(" MED SW: %s\n", nchassis->c_med_sw?nchassis->c_med_sw:"(null)"); | |
170 | printf(" MED SN: %s\n", nchassis->c_med_sn?nchassis->c_med_sn:"(null)"); | |
171 | printf(" MED manufacturer: %s\n", nchassis->c_med_manuf?nchassis->c_med_manuf:"(null)"); | |
172 | printf(" MED model: %s\n", nchassis->c_med_model?nchassis->c_med_model:"(null)"); | |
173 | printf(" MED asset: %s\n", nchassis->c_med_asset?nchassis->c_med_asset:"(null)"); | |
174 | #endif | |
175 | ||
176 | printf("Port:\n"); | |
177 | printf(" ID subtype: %" PRIu8 "\n", nport->p_id_subtype); | |
178 | printf(" ID: %s\n", tohex(nport->p_id, nport->p_id_len)); | |
179 | printf(" Description: %s\n", nport->p_descr?nport->p_descr:"(null)"); | |
180 | printf(" MFS: %" PRIu16 "\n", nport->p_mfs); | |
78346c89 | 181 | printf(" TTL: %" PRIu16 "\n", nport->p_ttl); |
dedb1eb0 VB |
182 | #ifdef ENABLE_DOT3 |
183 | printf(" Dot3 aggrID: %" PRIu32 "\n", nport->p_aggregid); | |
184 | printf(" Dot3 MAC/phy autoneg supported: %" PRIu8 "\n", nport->p_macphy.autoneg_support); | |
185 | printf(" Dot3 MAC/phy autoneg enabled: %" PRIu8 "\n", nport->p_macphy.autoneg_enabled); | |
186 | printf(" Dot3 MAC/phy autoneg advertised: %" PRIu16 "\n", nport->p_macphy.autoneg_advertised); | |
187 | printf(" Dot3 MAC/phy MAU type: %" PRIu16 "\n", nport->p_macphy.mau_type); | |
188 | printf(" Dot3 power device type: %" PRIu8 "\n", nport->p_power.devicetype); | |
189 | printf(" Dot3 power supported: %" PRIu8 "\n", nport->p_power.supported); | |
190 | printf(" Dot3 power enabled: %" PRIu8 "\n", nport->p_power.enabled); | |
191 | printf(" Dot3 power pair control: %" PRIu8 "\n", nport->p_power.paircontrol); | |
192 | printf(" Dot3 power pairs: %" PRIu8 "\n", nport->p_power.pairs); | |
193 | printf(" Dot3 power class: %" PRIu8 "\n", nport->p_power.class); | |
194 | printf(" Dot3 power type: %" PRIu8 "\n", nport->p_power.powertype); | |
195 | printf(" Dot3 power source: %" PRIu8 "\n", nport->p_power.source); | |
196 | printf(" Dot3 power priority: %" PRIu8 "\n", nport->p_power.priority); | |
197 | printf(" Dot3 power requested: %" PRIu16 "\n", nport->p_power.requested); | |
198 | printf(" Dot3 power allocated: %" PRIu16 "\n", nport->p_power.allocated); | |
199 | #endif | |
200 | #ifdef ENABLE_LLDPMED | |
201 | printf(" MED cap: %" PRIu16 "\n", nport->p_med_cap_enabled); | |
202 | for (int i = 0; i < LLDP_MED_APPTYPE_LAST; i++) { | |
203 | if (nport->p_med_policy[i].type == 0) continue; | |
204 | printf(" MED policy type: %" PRIu8 "\n", nport->p_med_policy[i].type); | |
205 | printf(" MED policy unknown: %" PRIu8 "\n", nport->p_med_policy[i].unknown); | |
206 | printf(" MED policy tagged: %" PRIu8 "\n", nport->p_med_policy[i].tagged); | |
207 | printf(" MED policy vid: %" PRIu16 "\n", nport->p_med_policy[i].vid); | |
208 | printf(" MED policy priority: %" PRIu8 "\n", nport->p_med_policy[i].priority); | |
209 | printf(" MED policy dscp: %" PRIu8 "\n", nport->p_med_policy[i].dscp); | |
210 | } | |
211 | for (int i = 0; i < LLDP_MED_LOCFORMAT_LAST; i++) { | |
212 | if (nport->p_med_location[i].format == 0) continue; | |
213 | printf(" MED location format: %" PRIu8 "\n", nport->p_med_location[i].format); | |
214 | printf(" MED location: %s\n", tohex(nport->p_med_location[i].data, | |
215 | nport->p_med_location[i].data_len)); | |
216 | } | |
217 | printf(" MED power device type: %" PRIu8 "\n", nport->p_med_power.devicetype); | |
218 | printf(" MED power source: %" PRIu8 "\n", nport->p_med_power.source); | |
219 | printf(" MED power priority: %" PRIu8 "\n", nport->p_med_power.priority); | |
220 | printf(" MED power value: %" PRIu16 "\n", nport->p_med_power.val); | |
221 | #endif | |
222 | #ifdef ENABLE_DOT1 | |
223 | printf(" Dot1 PVID: %" PRIu16 "\n", nport->p_pvid); | |
224 | struct lldpd_vlan *vlan; | |
225 | TAILQ_FOREACH(vlan, &nport->p_vlans, v_entries) { | |
226 | printf(" Dot1 VLAN: %s (%" PRIu16 ")\n", vlan->v_name, vlan->v_vid); | |
227 | } | |
228 | struct lldpd_ppvid *ppvid; | |
229 | TAILQ_FOREACH(ppvid, &nport->p_ppvids, p_entries) { | |
230 | printf(" Dot1 PPVID: %" PRIu16 " (status: %" PRIu8 ")\n", | |
231 | ppvid->p_ppvid, ppvid->p_cap_status); | |
232 | } | |
233 | struct lldpd_pi *pid; | |
234 | TAILQ_FOREACH(pid, &nport->p_pids, p_entries) { | |
235 | printf(" Dot1 PI: %s\n", tohex(pid->p_pi, pid->p_pi_len)); | |
236 | } | |
237 | #endif | |
238 | #ifdef ENABLE_CUSTOM | |
239 | struct lldpd_custom *custom; | |
240 | TAILQ_FOREACH(custom, &nport->p_custom_list, next) { | |
241 | printf(" Custom OUI: %s\n", | |
242 | tohex((char*)custom->oui, sizeof(custom->oui))); | |
243 | printf(" Custom subtype: %" PRIu8 "\n", custom->subtype); | |
244 | printf(" Custom info: %s\n", | |
245 | tohex((char*)custom->oui_info, custom->oui_info_len)); | |
246 | } | |
247 | #endif | |
248 | exit(0); | |
249 | } |