1cac3dcd5SXin LI /*
2cac3dcd5SXin LI * Copyright (c) 1998-2011 The TCPDUMP project
3cac3dcd5SXin LI *
4cac3dcd5SXin LI * Redistribution and use in source and binary forms, with or without
5cac3dcd5SXin LI * modification, are permitted provided that: (1) source code
6cac3dcd5SXin LI * distributions retain the above copyright notice and this paragraph
7cac3dcd5SXin LI * in its entirety, and (2) distributions including binary code include
8cac3dcd5SXin LI * the above copyright notice and this paragraph in its entirety in
9cac3dcd5SXin LI * the documentation or other materials provided with the distribution.
10cac3dcd5SXin LI * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
11cac3dcd5SXin LI * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
12cac3dcd5SXin LI * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13cac3dcd5SXin LI * FOR A PARTICULAR PURPOSE.
14cac3dcd5SXin LI *
150bff6a5aSEd Maste * Original code by Hannes Gredler (hannes@gredler.at)
16cac3dcd5SXin LI */
17cac3dcd5SXin LI
183340d773SGleb Smirnoff /* \summary: Resource Public Key Infrastructure (RPKI) to Router Protocol printer */
193340d773SGleb Smirnoff
203340d773SGleb Smirnoff /* specification: RFC 6810 */
213340d773SGleb Smirnoff
22ee67461eSJoseph Mingrone #include <config.h>
23cac3dcd5SXin LI
24ee67461eSJoseph Mingrone #include "netdissect-stdinc.h"
25cac3dcd5SXin LI
26ee67461eSJoseph Mingrone #define ND_LONGJMP_FROM_TCHECK
273340d773SGleb Smirnoff #include "netdissect.h"
28cac3dcd5SXin LI #include "extract.h"
29cac3dcd5SXin LI #include "addrtoname.h"
30cac3dcd5SXin LI
313340d773SGleb Smirnoff
32cac3dcd5SXin LI /*
33cac3dcd5SXin LI * RPKI/Router PDU header
34cac3dcd5SXin LI *
35cac3dcd5SXin LI * Here's what the PDU header looks like.
36cac3dcd5SXin LI * The length does include the version and length fields.
37cac3dcd5SXin LI */
38cac3dcd5SXin LI typedef struct rpki_rtr_pdu_ {
39ee67461eSJoseph Mingrone nd_uint8_t version; /* Version number */
40ee67461eSJoseph Mingrone nd_uint8_t pdu_type; /* PDU type */
41cac3dcd5SXin LI union {
42ee67461eSJoseph Mingrone nd_uint16_t session_id; /* Session id */
43ee67461eSJoseph Mingrone nd_uint16_t error_code; /* Error code */
44cac3dcd5SXin LI } u;
45ee67461eSJoseph Mingrone nd_uint32_t length;
46cac3dcd5SXin LI } rpki_rtr_pdu;
47cac3dcd5SXin LI
48cac3dcd5SXin LI /*
49cac3dcd5SXin LI * IPv4 Prefix PDU.
50cac3dcd5SXin LI */
51cac3dcd5SXin LI typedef struct rpki_rtr_pdu_ipv4_prefix_ {
52cac3dcd5SXin LI rpki_rtr_pdu pdu_header;
53ee67461eSJoseph Mingrone nd_uint8_t flags;
54ee67461eSJoseph Mingrone nd_uint8_t prefix_length;
55ee67461eSJoseph Mingrone nd_uint8_t max_length;
56ee67461eSJoseph Mingrone nd_uint8_t zero;
57ee67461eSJoseph Mingrone nd_ipv4 prefix;
58ee67461eSJoseph Mingrone nd_uint32_t as;
59cac3dcd5SXin LI } rpki_rtr_pdu_ipv4_prefix;
60cac3dcd5SXin LI
61cac3dcd5SXin LI /*
62cac3dcd5SXin LI * IPv6 Prefix PDU.
63cac3dcd5SXin LI */
64cac3dcd5SXin LI typedef struct rpki_rtr_pdu_ipv6_prefix_ {
65cac3dcd5SXin LI rpki_rtr_pdu pdu_header;
66ee67461eSJoseph Mingrone nd_uint8_t flags;
67ee67461eSJoseph Mingrone nd_uint8_t prefix_length;
68ee67461eSJoseph Mingrone nd_uint8_t max_length;
69ee67461eSJoseph Mingrone nd_uint8_t zero;
70ee67461eSJoseph Mingrone nd_ipv6 prefix;
71ee67461eSJoseph Mingrone nd_uint32_t as;
72cac3dcd5SXin LI } rpki_rtr_pdu_ipv6_prefix;
73cac3dcd5SXin LI
74cac3dcd5SXin LI /*
75cac3dcd5SXin LI * Error report PDU.
76cac3dcd5SXin LI */
77cac3dcd5SXin LI typedef struct rpki_rtr_pdu_error_report_ {
78cac3dcd5SXin LI rpki_rtr_pdu pdu_header;
79ee67461eSJoseph Mingrone nd_uint32_t encapsulated_pdu_length; /* Encapsulated PDU length */
800bff6a5aSEd Maste /* Copy of Erroneous PDU (variable, optional) */
810bff6a5aSEd Maste /* Length of Error Text (4 octets in network byte order) */
820bff6a5aSEd Maste /* Arbitrary Text of Error Diagnostic Message (variable, optional) */
83cac3dcd5SXin LI } rpki_rtr_pdu_error_report;
84cac3dcd5SXin LI
85cac3dcd5SXin LI /*
86cac3dcd5SXin LI * PDU type codes
87cac3dcd5SXin LI */
88cac3dcd5SXin LI #define RPKI_RTR_SERIAL_NOTIFY_PDU 0
89cac3dcd5SXin LI #define RPKI_RTR_SERIAL_QUERY_PDU 1
90cac3dcd5SXin LI #define RPKI_RTR_RESET_QUERY_PDU 2
91cac3dcd5SXin LI #define RPKI_RTR_CACHE_RESPONSE_PDU 3
92cac3dcd5SXin LI #define RPKI_RTR_IPV4_PREFIX_PDU 4
93cac3dcd5SXin LI #define RPKI_RTR_IPV6_PREFIX_PDU 6
94cac3dcd5SXin LI #define RPKI_RTR_END_OF_DATA_PDU 7
95cac3dcd5SXin LI #define RPKI_RTR_CACHE_RESET_PDU 8
96cac3dcd5SXin LI #define RPKI_RTR_ERROR_REPORT_PDU 10
97cac3dcd5SXin LI
98cac3dcd5SXin LI static const struct tok rpki_rtr_pdu_values[] = {
99cac3dcd5SXin LI { RPKI_RTR_SERIAL_NOTIFY_PDU, "Serial Notify" },
100cac3dcd5SXin LI { RPKI_RTR_SERIAL_QUERY_PDU, "Serial Query" },
101cac3dcd5SXin LI { RPKI_RTR_RESET_QUERY_PDU, "Reset Query" },
102cac3dcd5SXin LI { RPKI_RTR_CACHE_RESPONSE_PDU, "Cache Response" },
103cac3dcd5SXin LI { RPKI_RTR_IPV4_PREFIX_PDU, "IPV4 Prefix" },
104cac3dcd5SXin LI { RPKI_RTR_IPV6_PREFIX_PDU, "IPV6 Prefix" },
105cac3dcd5SXin LI { RPKI_RTR_END_OF_DATA_PDU, "End of Data" },
106cac3dcd5SXin LI { RPKI_RTR_CACHE_RESET_PDU, "Cache Reset" },
107cac3dcd5SXin LI { RPKI_RTR_ERROR_REPORT_PDU, "Error Report" },
108cac3dcd5SXin LI { 0, NULL}
109cac3dcd5SXin LI };
110cac3dcd5SXin LI
111cac3dcd5SXin LI static const struct tok rpki_rtr_error_codes[] = {
112cac3dcd5SXin LI { 0, "Corrupt Data" },
113cac3dcd5SXin LI { 1, "Internal Error" },
114cac3dcd5SXin LI { 2, "No Data Available" },
115cac3dcd5SXin LI { 3, "Invalid Request" },
116cac3dcd5SXin LI { 4, "Unsupported Protocol Version" },
117cac3dcd5SXin LI { 5, "Unsupported PDU Type" },
118cac3dcd5SXin LI { 6, "Withdrawal of Unknown Record" },
119cac3dcd5SXin LI { 7, "Duplicate Announcement Received" },
120cac3dcd5SXin LI { 0, NULL}
121cac3dcd5SXin LI };
122cac3dcd5SXin LI
123cac3dcd5SXin LI /*
1248bdc5a62SPatrick Kelsey * Build a indentation string for a given indentation level.
125cac3dcd5SXin LI * XXX this should be really in util.c
126cac3dcd5SXin LI */
127cac3dcd5SXin LI static char *
indent_string(u_int indent)128cac3dcd5SXin LI indent_string (u_int indent)
129cac3dcd5SXin LI {
130cac3dcd5SXin LI static char buf[20];
131cac3dcd5SXin LI u_int idx;
132cac3dcd5SXin LI
133cac3dcd5SXin LI idx = 0;
134cac3dcd5SXin LI buf[idx] = '\0';
135cac3dcd5SXin LI
136cac3dcd5SXin LI /*
137cac3dcd5SXin LI * Does the static buffer fit ?
138cac3dcd5SXin LI */
139cac3dcd5SXin LI if (sizeof(buf) < ((indent/8) + (indent %8) + 2)) {
140cac3dcd5SXin LI return buf;
141cac3dcd5SXin LI }
142cac3dcd5SXin LI
143cac3dcd5SXin LI /*
144cac3dcd5SXin LI * Heading newline.
145cac3dcd5SXin LI */
146cac3dcd5SXin LI buf[idx] = '\n';
147cac3dcd5SXin LI idx++;
148cac3dcd5SXin LI
149cac3dcd5SXin LI while (indent >= 8) {
150cac3dcd5SXin LI buf[idx] = '\t';
151cac3dcd5SXin LI idx++;
152cac3dcd5SXin LI indent -= 8;
153cac3dcd5SXin LI }
154cac3dcd5SXin LI
155cac3dcd5SXin LI while (indent > 0) {
156cac3dcd5SXin LI buf[idx] = ' ';
157cac3dcd5SXin LI idx++;
158cac3dcd5SXin LI indent--;
159cac3dcd5SXin LI }
160cac3dcd5SXin LI
161cac3dcd5SXin LI /*
162cac3dcd5SXin LI * Trailing zero.
163cac3dcd5SXin LI */
164cac3dcd5SXin LI buf[idx] = '\0';
165cac3dcd5SXin LI
166cac3dcd5SXin LI return buf;
167cac3dcd5SXin LI }
168cac3dcd5SXin LI
169cac3dcd5SXin LI /*
170cac3dcd5SXin LI * Print a single PDU.
171cac3dcd5SXin LI */
1720bff6a5aSEd Maste static u_int
rpki_rtr_pdu_print(netdissect_options * ndo,const u_char * tptr,const u_int len,const u_char recurse,const u_int indent)1730bff6a5aSEd Maste rpki_rtr_pdu_print(netdissect_options *ndo, const u_char *tptr, const u_int len,
1740bff6a5aSEd Maste const u_char recurse, const u_int indent)
175cac3dcd5SXin LI {
176cac3dcd5SXin LI const rpki_rtr_pdu *pdu_header;
177cac3dcd5SXin LI u_int pdu_type, pdu_len, hexdump;
178cac3dcd5SXin LI const u_char *msg;
179*0a7e5f1fSJoseph Mingrone uint8_t pdu_ver;
180cac3dcd5SXin LI
181*0a7e5f1fSJoseph Mingrone if (len < sizeof(rpki_rtr_pdu)) {
182*0a7e5f1fSJoseph Mingrone ND_PRINT("(%u bytes is too few to decode)", len);
183*0a7e5f1fSJoseph Mingrone goto invalid;
184*0a7e5f1fSJoseph Mingrone }
185*0a7e5f1fSJoseph Mingrone pdu_header = (const rpki_rtr_pdu *)tptr;
186*0a7e5f1fSJoseph Mingrone pdu_ver = GET_U_1(pdu_header->version);
187*0a7e5f1fSJoseph Mingrone if (pdu_ver != 0) {
1880bff6a5aSEd Maste /* Skip the rest of the input buffer because even if this is
1890bff6a5aSEd Maste * a well-formed PDU of a future RPKI-Router protocol version
1900bff6a5aSEd Maste * followed by a well-formed PDU of RPKI-Router protocol
1910bff6a5aSEd Maste * version 0, there is no way to know exactly how to skip the
1920bff6a5aSEd Maste * current PDU.
1930bff6a5aSEd Maste */
194*0a7e5f1fSJoseph Mingrone ND_PRINT("%sRPKI-RTRv%u (unknown)", indent_string(8), pdu_ver);
1950bff6a5aSEd Maste return len;
1960bff6a5aSEd Maste }
197ee67461eSJoseph Mingrone pdu_type = GET_U_1(pdu_header->pdu_type);
198ee67461eSJoseph Mingrone pdu_len = GET_BE_U_4(pdu_header->length);
1990bff6a5aSEd Maste /* Do not check bounds with pdu_len yet, do it in the case blocks
2000bff6a5aSEd Maste * below to make it possible to decode at least the beginning of
2010bff6a5aSEd Maste * a truncated Error Report PDU or a truncated encapsulated PDU.
2020bff6a5aSEd Maste */
203cac3dcd5SXin LI hexdump = FALSE;
204cac3dcd5SXin LI
205ee67461eSJoseph Mingrone ND_PRINT("%sRPKI-RTRv%u, %s PDU (%u), length: %u",
206cac3dcd5SXin LI indent_string(8),
207*0a7e5f1fSJoseph Mingrone pdu_ver,
208cac3dcd5SXin LI tok2str(rpki_rtr_pdu_values, "Unknown", pdu_type),
209ee67461eSJoseph Mingrone pdu_type, pdu_len);
2100bff6a5aSEd Maste if (pdu_len < sizeof(rpki_rtr_pdu) || pdu_len > len)
2110bff6a5aSEd Maste goto invalid;
212cac3dcd5SXin LI
213cac3dcd5SXin LI switch (pdu_type) {
214cac3dcd5SXin LI
215cac3dcd5SXin LI /*
216cac3dcd5SXin LI * The following PDUs share the message format.
217cac3dcd5SXin LI */
218cac3dcd5SXin LI case RPKI_RTR_SERIAL_NOTIFY_PDU:
219cac3dcd5SXin LI case RPKI_RTR_SERIAL_QUERY_PDU:
220cac3dcd5SXin LI case RPKI_RTR_END_OF_DATA_PDU:
2210bff6a5aSEd Maste if (pdu_len != sizeof(rpki_rtr_pdu) + 4)
2220bff6a5aSEd Maste goto invalid;
223cac3dcd5SXin LI msg = (const u_char *)(pdu_header + 1);
224ee67461eSJoseph Mingrone ND_PRINT("%sSession ID: 0x%04x, Serial: %u",
225cac3dcd5SXin LI indent_string(indent+2),
226ee67461eSJoseph Mingrone GET_BE_U_2(pdu_header->u.session_id),
227ee67461eSJoseph Mingrone GET_BE_U_4(msg));
228cac3dcd5SXin LI break;
229cac3dcd5SXin LI
230cac3dcd5SXin LI /*
231cac3dcd5SXin LI * The following PDUs share the message format.
232cac3dcd5SXin LI */
233cac3dcd5SXin LI case RPKI_RTR_RESET_QUERY_PDU:
234cac3dcd5SXin LI case RPKI_RTR_CACHE_RESET_PDU:
2350bff6a5aSEd Maste if (pdu_len != sizeof(rpki_rtr_pdu))
2360bff6a5aSEd Maste goto invalid;
2370bff6a5aSEd Maste /* no additional boundary to check */
238cac3dcd5SXin LI
239cac3dcd5SXin LI /*
240cac3dcd5SXin LI * Zero payload PDUs.
241cac3dcd5SXin LI */
242cac3dcd5SXin LI break;
243cac3dcd5SXin LI
244cac3dcd5SXin LI case RPKI_RTR_CACHE_RESPONSE_PDU:
2450bff6a5aSEd Maste if (pdu_len != sizeof(rpki_rtr_pdu))
2460bff6a5aSEd Maste goto invalid;
2470bff6a5aSEd Maste /* no additional boundary to check */
248ee67461eSJoseph Mingrone ND_PRINT("%sSession ID: 0x%04x",
249cac3dcd5SXin LI indent_string(indent+2),
250ee67461eSJoseph Mingrone GET_BE_U_2(pdu_header->u.session_id));
251cac3dcd5SXin LI break;
252cac3dcd5SXin LI
253cac3dcd5SXin LI case RPKI_RTR_IPV4_PREFIX_PDU:
254cac3dcd5SXin LI {
2553340d773SGleb Smirnoff const rpki_rtr_pdu_ipv4_prefix *pdu;
256cac3dcd5SXin LI
257ee67461eSJoseph Mingrone if (pdu_len != sizeof(rpki_rtr_pdu_ipv4_prefix))
2580bff6a5aSEd Maste goto invalid;
2593340d773SGleb Smirnoff pdu = (const rpki_rtr_pdu_ipv4_prefix *)tptr;
260ee67461eSJoseph Mingrone ND_PRINT("%sIPv4 Prefix %s/%u-%u, origin-as %u, flags 0x%02x",
261cac3dcd5SXin LI indent_string(indent+2),
262ee67461eSJoseph Mingrone GET_IPADDR_STRING(pdu->prefix),
263ee67461eSJoseph Mingrone GET_U_1(pdu->prefix_length), GET_U_1(pdu->max_length),
264ee67461eSJoseph Mingrone GET_BE_U_4(pdu->as), GET_U_1(pdu->flags));
265cac3dcd5SXin LI }
266cac3dcd5SXin LI break;
267cac3dcd5SXin LI
268cac3dcd5SXin LI case RPKI_RTR_IPV6_PREFIX_PDU:
269cac3dcd5SXin LI {
2703340d773SGleb Smirnoff const rpki_rtr_pdu_ipv6_prefix *pdu;
271cac3dcd5SXin LI
272ee67461eSJoseph Mingrone if (pdu_len != sizeof(rpki_rtr_pdu_ipv6_prefix))
2730bff6a5aSEd Maste goto invalid;
2743340d773SGleb Smirnoff pdu = (const rpki_rtr_pdu_ipv6_prefix *)tptr;
275ee67461eSJoseph Mingrone ND_PRINT("%sIPv6 Prefix %s/%u-%u, origin-as %u, flags 0x%02x",
276cac3dcd5SXin LI indent_string(indent+2),
277ee67461eSJoseph Mingrone GET_IP6ADDR_STRING(pdu->prefix),
278ee67461eSJoseph Mingrone GET_U_1(pdu->prefix_length), GET_U_1(pdu->max_length),
279ee67461eSJoseph Mingrone GET_BE_U_4(pdu->as), GET_U_1(pdu->flags));
280cac3dcd5SXin LI }
281cac3dcd5SXin LI break;
282cac3dcd5SXin LI
283cac3dcd5SXin LI case RPKI_RTR_ERROR_REPORT_PDU:
284cac3dcd5SXin LI {
2853340d773SGleb Smirnoff const rpki_rtr_pdu_error_report *pdu;
286cac3dcd5SXin LI u_int encapsulated_pdu_length, text_length, tlen, error_code;
287cac3dcd5SXin LI
2880bff6a5aSEd Maste tlen = sizeof(rpki_rtr_pdu);
2890bff6a5aSEd Maste /* Do not test for the "Length of Error Text" data element yet. */
2900bff6a5aSEd Maste if (pdu_len < tlen + 4)
2910bff6a5aSEd Maste goto invalid;
2923340d773SGleb Smirnoff pdu = (const rpki_rtr_pdu_error_report *)tptr;
293ee67461eSJoseph Mingrone encapsulated_pdu_length = GET_BE_U_4(pdu->encapsulated_pdu_length);
2940bff6a5aSEd Maste tlen += 4;
295*0a7e5f1fSJoseph Mingrone /* Safe up to and including the "Length of Encapsulated PDU"
296*0a7e5f1fSJoseph Mingrone * data element, more data elements may be present.
297*0a7e5f1fSJoseph Mingrone */
298cac3dcd5SXin LI
299ee67461eSJoseph Mingrone error_code = GET_BE_U_2(pdu->pdu_header.u.error_code);
300ee67461eSJoseph Mingrone ND_PRINT("%sError code: %s (%u), Encapsulated PDU length: %u",
301cac3dcd5SXin LI indent_string(indent+2),
302cac3dcd5SXin LI tok2str(rpki_rtr_error_codes, "Unknown", error_code),
303ee67461eSJoseph Mingrone error_code, encapsulated_pdu_length);
304cac3dcd5SXin LI
3050bff6a5aSEd Maste if (encapsulated_pdu_length) {
3060bff6a5aSEd Maste /* Section 5.10 of RFC 6810 says:
3070bff6a5aSEd Maste * "An Error Report PDU MUST NOT be sent for an Error Report PDU."
3080bff6a5aSEd Maste *
3090bff6a5aSEd Maste * However, as far as the protocol encoding goes Error Report PDUs can
3100bff6a5aSEd Maste * happen to be nested in each other, however many times, in which case
3110bff6a5aSEd Maste * the decoder should still print such semantically incorrect PDUs.
3120bff6a5aSEd Maste *
3130bff6a5aSEd Maste * That said, "the Erroneous PDU field MAY be truncated" (ibid), thus
3140bff6a5aSEd Maste * to keep things simple this implementation decodes only the two
3150bff6a5aSEd Maste * outermost layers of PDUs and makes bounds checks in the outer and
3160bff6a5aSEd Maste * the inner PDU independently.
317cac3dcd5SXin LI */
3180bff6a5aSEd Maste if (pdu_len < tlen + encapsulated_pdu_length)
3190bff6a5aSEd Maste goto invalid;
3200bff6a5aSEd Maste if (! recurse) {
321ee67461eSJoseph Mingrone ND_TCHECK_LEN(tptr, tlen + encapsulated_pdu_length);
322*0a7e5f1fSJoseph Mingrone } else {
323ee67461eSJoseph Mingrone ND_PRINT("%s-----encapsulated PDU-----", indent_string(indent+4));
3240bff6a5aSEd Maste rpki_rtr_pdu_print(ndo, tptr + tlen,
3250bff6a5aSEd Maste encapsulated_pdu_length, 0, indent + 2);
3260bff6a5aSEd Maste }
3270bff6a5aSEd Maste tlen += encapsulated_pdu_length;
328cac3dcd5SXin LI }
329cac3dcd5SXin LI
3300bff6a5aSEd Maste if (pdu_len < tlen + 4)
3310bff6a5aSEd Maste goto invalid;
332cac3dcd5SXin LI /*
333cac3dcd5SXin LI * Extract, trail-zero and print the Error message.
334cac3dcd5SXin LI */
335ee67461eSJoseph Mingrone text_length = GET_BE_U_4(tptr + tlen);
3360bff6a5aSEd Maste tlen += 4;
337*0a7e5f1fSJoseph Mingrone /* Safe up to and including the "Length of Error Text" data element,
338*0a7e5f1fSJoseph Mingrone * one more data element may be present.
339*0a7e5f1fSJoseph Mingrone */
3400bff6a5aSEd Maste
3410bff6a5aSEd Maste if (text_length) {
3420bff6a5aSEd Maste if (pdu_len < tlen + text_length)
3430bff6a5aSEd Maste goto invalid;
344ee67461eSJoseph Mingrone /* nd_printn() makes the bounds check */
345ee67461eSJoseph Mingrone ND_PRINT("%sError text: ", indent_string(indent+2));
346ee67461eSJoseph Mingrone (void)nd_printn(ndo, tptr + tlen, text_length, NULL);
347cac3dcd5SXin LI }
348cac3dcd5SXin LI }
349cac3dcd5SXin LI break;
350cac3dcd5SXin LI
351cac3dcd5SXin LI default:
352ee67461eSJoseph Mingrone ND_TCHECK_LEN(tptr, pdu_len);
353cac3dcd5SXin LI
354cac3dcd5SXin LI /*
355cac3dcd5SXin LI * Unknown data, please hexdump.
356cac3dcd5SXin LI */
357cac3dcd5SXin LI hexdump = TRUE;
358cac3dcd5SXin LI }
359cac3dcd5SXin LI
360cac3dcd5SXin LI /* do we also want to see a hex dump ? */
3613c602fabSXin LI if (ndo->ndo_vflag > 1 || (ndo->ndo_vflag && hexdump)) {
3623c602fabSXin LI print_unknown_data(ndo,tptr,"\n\t ", pdu_len);
363cac3dcd5SXin LI }
3640bff6a5aSEd Maste return pdu_len;
3658bdc5a62SPatrick Kelsey
3660bff6a5aSEd Maste invalid:
367ee67461eSJoseph Mingrone nd_print_invalid(ndo);
368ee67461eSJoseph Mingrone ND_TCHECK_LEN(tptr, len);
3690bff6a5aSEd Maste return len;
370cac3dcd5SXin LI }
371cac3dcd5SXin LI
372cac3dcd5SXin LI void
rpki_rtr_print(netdissect_options * ndo,const u_char * pptr,u_int len)373ee67461eSJoseph Mingrone rpki_rtr_print(netdissect_options *ndo, const u_char *pptr, u_int len)
3748bdc5a62SPatrick Kelsey {
375ee67461eSJoseph Mingrone ndo->ndo_protocol = "rpki_rtr";
3763c602fabSXin LI if (!ndo->ndo_vflag) {
377ee67461eSJoseph Mingrone ND_PRINT(", RPKI-RTR");
378cac3dcd5SXin LI return;
379cac3dcd5SXin LI }
3800bff6a5aSEd Maste while (len) {
3810bff6a5aSEd Maste u_int pdu_len = rpki_rtr_pdu_print(ndo, pptr, len, 1, 8);
3820bff6a5aSEd Maste len -= pdu_len;
3830bff6a5aSEd Maste pptr += pdu_len;
384cac3dcd5SXin LI }
385cac3dcd5SXin LI }
386