print-dccp.c revision 356341
1/*
2 * Copyright (C) Arnaldo Carvalho de Melo 2004
3 * Copyright (C) Ian McDonald 2005
4 * Copyright (C) Yoshifumi Nishida 2005
5 *
6 * This software may be distributed either under the terms of the
7 * BSD-style license that accompanies tcpdump or the GNU GPL version 2
8 */
9
10/* \summary: Datagram Congestion Control Protocol (DCCP) printer */
11
12#ifdef HAVE_CONFIG_H
13#include "config.h"
14#endif
15
16#include <netdissect-stdinc.h>
17
18#include <stdio.h>
19#include <string.h>
20
21#include "netdissect.h"
22#include "addrtoname.h"
23#include "extract.h"
24#include "ip.h"
25#include "ip6.h"
26#include "ipproto.h"
27
28/* RFC4340: Datagram Congestion Control Protocol (DCCP) */
29
30/**
31 * struct dccp_hdr - generic part of DCCP packet header, with a 24-bit
32 * sequence number
33 *
34 * @dccph_sport - Relevant port on the endpoint that sent this packet
35 * @dccph_dport - Relevant port on the other endpoint
36 * @dccph_doff - Data Offset from the start of the DCCP header, in 32-bit words
37 * @dccph_ccval - Used by the HC-Sender CCID
38 * @dccph_cscov - Parts of the packet that are covered by the Checksum field
39 * @dccph_checksum - Internet checksum, depends on dccph_cscov
40 * @dccph_x - 0 = 24 bit sequence number, 1 = 48
41 * @dccph_type - packet type, see DCCP_PKT_ prefixed macros
42 * @dccph_seq - 24-bit sequence number
43 */
44struct dccp_hdr {
45	uint16_t	dccph_sport,
46			dccph_dport;
47	uint8_t		dccph_doff;
48	uint8_t		dccph_ccval_cscov;
49	uint16_t	dccph_checksum;
50	uint8_t		dccph_xtr;
51	uint8_t		dccph_seq[3];
52} UNALIGNED;
53
54/**
55 * struct dccp_hdr_ext - generic part of DCCP packet header, with a 48-bit
56 * sequence number
57 *
58 * @dccph_sport - Relevant port on the endpoint that sent this packet
59 * @dccph_dport - Relevant port on the other endpoint
60 * @dccph_doff - Data Offset from the start of the DCCP header, in 32-bit words
61 * @dccph_ccval - Used by the HC-Sender CCID
62 * @dccph_cscov - Parts of the packet that are covered by the Checksum field
63 * @dccph_checksum - Internet checksum, depends on dccph_cscov
64 * @dccph_x - 0 = 24 bit sequence number, 1 = 48
65 * @dccph_type - packet type, see DCCP_PKT_ prefixed macros
66 * @dccph_seq - 48-bit sequence number
67 */
68struct dccp_hdr_ext {
69	uint16_t	dccph_sport,
70			dccph_dport;
71	uint8_t		dccph_doff;
72	uint8_t		dccph_ccval_cscov;
73	uint16_t	dccph_checksum;
74	uint8_t		dccph_xtr;
75	uint8_t		reserved;
76	uint8_t		dccph_seq[6];
77} UNALIGNED;
78
79#define DCCPH_CCVAL(dh)	(((dh)->dccph_ccval_cscov >> 4) & 0xF)
80#define DCCPH_CSCOV(dh)	(((dh)->dccph_ccval_cscov) & 0xF)
81
82#define DCCPH_X(dh)	((dh)->dccph_xtr & 1)
83#define DCCPH_TYPE(dh)	(((dh)->dccph_xtr >> 1) & 0xF)
84
85/**
86 * struct dccp_hdr_request - Conection initiation request header
87 *
88 * @dccph_req_service - Service to which the client app wants to connect
89 */
90struct dccp_hdr_request {
91	uint32_t	dccph_req_service;
92} UNALIGNED;
93
94/**
95 * struct dccp_hdr_response - Conection initiation response header
96 *
97 * @dccph_resp_ack - 48 bit ack number, contains GSR
98 * @dccph_resp_service - Echoes the Service Code on a received DCCP-Request
99 */
100struct dccp_hdr_response {
101	uint8_t				dccph_resp_ack[8];	/* always 8 bytes */
102	uint32_t			dccph_resp_service;
103} UNALIGNED;
104
105/**
106 * struct dccp_hdr_reset - Unconditionally shut down a connection
107 *
108 * @dccph_resp_ack - 48 bit ack number
109 * @dccph_reset_service - Echoes the Service Code on a received DCCP-Request
110 */
111struct dccp_hdr_reset {
112	uint8_t				dccph_reset_ack[8];	/* always 8 bytes */
113	uint8_t				dccph_reset_code,
114					dccph_reset_data[3];
115} UNALIGNED;
116
117enum dccp_pkt_type {
118	DCCP_PKT_REQUEST = 0,
119	DCCP_PKT_RESPONSE,
120	DCCP_PKT_DATA,
121	DCCP_PKT_ACK,
122	DCCP_PKT_DATAACK,
123	DCCP_PKT_CLOSEREQ,
124	DCCP_PKT_CLOSE,
125	DCCP_PKT_RESET,
126	DCCP_PKT_SYNC,
127	DCCP_PKT_SYNCACK
128};
129
130static const struct tok dccp_pkt_type_str[] = {
131	{ DCCP_PKT_REQUEST, "DCCP-Request" },
132	{ DCCP_PKT_RESPONSE, "DCCP-Response" },
133	{ DCCP_PKT_DATA, "DCCP-Data" },
134	{ DCCP_PKT_ACK, "DCCP-Ack" },
135	{ DCCP_PKT_DATAACK, "DCCP-DataAck" },
136	{ DCCP_PKT_CLOSEREQ, "DCCP-CloseReq" },
137	{ DCCP_PKT_CLOSE, "DCCP-Close" },
138	{ DCCP_PKT_RESET, "DCCP-Reset" },
139	{ DCCP_PKT_SYNC, "DCCP-Sync" },
140	{ DCCP_PKT_SYNCACK, "DCCP-SyncAck" },
141	{ 0, NULL}
142};
143
144enum dccp_reset_codes {
145	DCCP_RESET_CODE_UNSPECIFIED = 0,
146	DCCP_RESET_CODE_CLOSED,
147	DCCP_RESET_CODE_ABORTED,
148	DCCP_RESET_CODE_NO_CONNECTION,
149	DCCP_RESET_CODE_PACKET_ERROR,
150	DCCP_RESET_CODE_OPTION_ERROR,
151	DCCP_RESET_CODE_MANDATORY_ERROR,
152	DCCP_RESET_CODE_CONNECTION_REFUSED,
153	DCCP_RESET_CODE_BAD_SERVICE_CODE,
154	DCCP_RESET_CODE_TOO_BUSY,
155	DCCP_RESET_CODE_BAD_INIT_COOKIE,
156	DCCP_RESET_CODE_AGGRESSION_PENALTY,
157	__DCCP_RESET_CODE_LAST
158};
159
160static const char tstr[] = "[|dccp]";
161
162static const char *dccp_reset_codes[] = {
163	"unspecified",
164	"closed",
165	"aborted",
166	"no_connection",
167	"packet_error",
168	"option_error",
169	"mandatory_error",
170	"connection_refused",
171	"bad_service_code",
172	"too_busy",
173	"bad_init_cookie",
174	"aggression_penalty",
175};
176
177static const char *dccp_feature_nums[] = {
178	"reserved",
179	"ccid",
180	"allow_short_seqno",
181	"sequence_window",
182	"ecn_incapable",
183	"ack_ratio",
184	"send_ack_vector",
185	"send_ndp_count",
186	"minimum checksum coverage",
187	"check data checksum",
188};
189
190static inline u_int dccp_csum_coverage(const struct dccp_hdr* dh, u_int len)
191{
192	u_int cov;
193
194	if (DCCPH_CSCOV(dh) == 0)
195		return len;
196	cov = (dh->dccph_doff + DCCPH_CSCOV(dh) - 1) * sizeof(uint32_t);
197	return (cov > len)? len : cov;
198}
199
200static int dccp_cksum(netdissect_options *ndo, const struct ip *ip,
201	const struct dccp_hdr *dh, u_int len)
202{
203	return nextproto4_cksum(ndo, ip, (const uint8_t *)(const void *)dh, len,
204				dccp_csum_coverage(dh, len), IPPROTO_DCCP);
205}
206
207static int dccp6_cksum(netdissect_options *ndo, const struct ip6_hdr *ip6,
208	const struct dccp_hdr *dh, u_int len)
209{
210	return nextproto6_cksum(ndo, ip6, (const uint8_t *)(const void *)dh, len,
211				dccp_csum_coverage(dh, len), IPPROTO_DCCP);
212}
213
214static const char *dccp_reset_code(uint8_t code)
215{
216	if (code >= __DCCP_RESET_CODE_LAST)
217		return "invalid";
218	return dccp_reset_codes[code];
219}
220
221static uint64_t dccp_seqno(const u_char *bp)
222{
223	const struct dccp_hdr *dh = (const struct dccp_hdr *)bp;
224	uint64_t seqno;
225
226	if (DCCPH_X(dh) != 0) {
227		const struct dccp_hdr_ext *dhx = (const struct dccp_hdr_ext *)bp;
228		seqno = EXTRACT_48BITS(dhx->dccph_seq);
229	} else {
230		seqno = EXTRACT_24BITS(dh->dccph_seq);
231	}
232
233	return seqno;
234}
235
236static inline unsigned int dccp_basic_hdr_len(const struct dccp_hdr *dh)
237{
238	return DCCPH_X(dh) ? sizeof(struct dccp_hdr_ext) : sizeof(struct dccp_hdr);
239}
240
241static void dccp_print_ack_no(netdissect_options *ndo, const u_char *bp)
242{
243	const struct dccp_hdr *dh = (const struct dccp_hdr *)bp;
244	const u_char *ackp = bp + dccp_basic_hdr_len(dh);
245	uint64_t ackno;
246
247	if (DCCPH_X(dh) != 0) {
248		ND_TCHECK2(*ackp, 8);
249		ackno = EXTRACT_48BITS(ackp + 2);
250	} else {
251		ND_TCHECK2(*ackp, 4);
252		ackno = EXTRACT_24BITS(ackp + 1);
253	}
254
255	ND_PRINT((ndo, "(ack=%" PRIu64 ") ", ackno));
256trunc:
257	return;
258}
259
260static int dccp_print_option(netdissect_options *, const u_char *, u_int);
261
262/**
263 * dccp_print - show dccp packet
264 * @bp - beginning of dccp packet
265 * @data2 - beginning of enclosing
266 * @len - lenght of ip packet
267 */
268void dccp_print(netdissect_options *ndo, const u_char *bp, const u_char *data2,
269		u_int len)
270{
271	const struct dccp_hdr *dh;
272	const struct ip *ip;
273	const struct ip6_hdr *ip6;
274	const u_char *cp;
275	u_short sport, dport;
276	u_int hlen;
277	u_int fixed_hdrlen;
278	uint8_t	dccph_type;
279
280	dh = (const struct dccp_hdr *)bp;
281
282	ip = (const struct ip *)data2;
283	if (IP_V(ip) == 6)
284		ip6 = (const struct ip6_hdr *)data2;
285	else
286		ip6 = NULL;
287
288	/* make sure we have enough data to look at the X bit */
289	cp = (const u_char *)(dh + 1);
290	if (cp > ndo->ndo_snapend) {
291		ND_PRINT((ndo, "[Invalid packet|dccp]"));
292		return;
293	}
294	if (len < sizeof(struct dccp_hdr)) {
295		ND_PRINT((ndo, "truncated-dccp - %u bytes missing!",
296			  len - (u_int)sizeof(struct dccp_hdr)));
297		return;
298	}
299
300	/* get the length of the generic header */
301	fixed_hdrlen = dccp_basic_hdr_len(dh);
302	if (len < fixed_hdrlen) {
303		ND_PRINT((ndo, "truncated-dccp - %u bytes missing!",
304			  len - fixed_hdrlen));
305		return;
306	}
307	ND_TCHECK2(*dh, fixed_hdrlen);
308
309	sport = EXTRACT_16BITS(&dh->dccph_sport);
310	dport = EXTRACT_16BITS(&dh->dccph_dport);
311	hlen = dh->dccph_doff * 4;
312
313	if (ip6) {
314		ND_PRINT((ndo, "%s.%d > %s.%d: ",
315			  ip6addr_string(ndo, &ip6->ip6_src), sport,
316			  ip6addr_string(ndo, &ip6->ip6_dst), dport));
317	} else {
318		ND_PRINT((ndo, "%s.%d > %s.%d: ",
319			  ipaddr_string(ndo, &ip->ip_src), sport,
320			  ipaddr_string(ndo, &ip->ip_dst), dport));
321	}
322
323	ND_PRINT((ndo, "DCCP"));
324
325	if (ndo->ndo_qflag) {
326		ND_PRINT((ndo, " %d", len - hlen));
327		if (hlen > len) {
328			ND_PRINT((ndo, " [bad hdr length %u - too long, > %u]",
329				  hlen, len));
330		}
331		return;
332	}
333
334	/* other variables in generic header */
335	if (ndo->ndo_vflag) {
336		ND_PRINT((ndo, " (CCVal %d, CsCov %d, ", DCCPH_CCVAL(dh), DCCPH_CSCOV(dh)));
337	}
338
339	/* checksum calculation */
340	if (ndo->ndo_vflag && ND_TTEST2(bp[0], len)) {
341		uint16_t sum = 0, dccp_sum;
342
343		dccp_sum = EXTRACT_16BITS(&dh->dccph_checksum);
344		ND_PRINT((ndo, "cksum 0x%04x ", dccp_sum));
345		if (IP_V(ip) == 4)
346			sum = dccp_cksum(ndo, ip, dh, len);
347		else if (IP_V(ip) == 6)
348			sum = dccp6_cksum(ndo, ip6, dh, len);
349		if (sum != 0)
350			ND_PRINT((ndo, "(incorrect -> 0x%04x)",in_cksum_shouldbe(dccp_sum, sum)));
351		else
352			ND_PRINT((ndo, "(correct)"));
353	}
354
355	if (ndo->ndo_vflag)
356		ND_PRINT((ndo, ")"));
357	ND_PRINT((ndo, " "));
358
359	dccph_type = DCCPH_TYPE(dh);
360	switch (dccph_type) {
361	case DCCP_PKT_REQUEST: {
362		const struct dccp_hdr_request *dhr =
363			(const struct dccp_hdr_request *)(bp + fixed_hdrlen);
364		fixed_hdrlen += 4;
365		if (len < fixed_hdrlen) {
366			ND_PRINT((ndo, "truncated-%s - %u bytes missing!",
367				  tok2str(dccp_pkt_type_str, "", dccph_type),
368				  len - fixed_hdrlen));
369			return;
370		}
371		ND_TCHECK(*dhr);
372		ND_PRINT((ndo, "%s (service=%d) ",
373			  tok2str(dccp_pkt_type_str, "", dccph_type),
374			  EXTRACT_32BITS(&dhr->dccph_req_service)));
375		break;
376	}
377	case DCCP_PKT_RESPONSE: {
378		const struct dccp_hdr_response *dhr =
379			(const struct dccp_hdr_response *)(bp + fixed_hdrlen);
380		fixed_hdrlen += 12;
381		if (len < fixed_hdrlen) {
382			ND_PRINT((ndo, "truncated-%s - %u bytes missing!",
383				  tok2str(dccp_pkt_type_str, "", dccph_type),
384				  len - fixed_hdrlen));
385			return;
386		}
387		ND_TCHECK(*dhr);
388		ND_PRINT((ndo, "%s (service=%d) ",
389			  tok2str(dccp_pkt_type_str, "", dccph_type),
390			  EXTRACT_32BITS(&dhr->dccph_resp_service)));
391		break;
392	}
393	case DCCP_PKT_DATA:
394		ND_PRINT((ndo, "%s ", tok2str(dccp_pkt_type_str, "", dccph_type)));
395		break;
396	case DCCP_PKT_ACK: {
397		fixed_hdrlen += 8;
398		if (len < fixed_hdrlen) {
399			ND_PRINT((ndo, "truncated-%s - %u bytes missing!",
400				  tok2str(dccp_pkt_type_str, "", dccph_type),
401				  len - fixed_hdrlen));
402			return;
403		}
404		ND_PRINT((ndo, "%s ", tok2str(dccp_pkt_type_str, "", dccph_type)));
405		break;
406	}
407	case DCCP_PKT_DATAACK: {
408		fixed_hdrlen += 8;
409		if (len < fixed_hdrlen) {
410			ND_PRINT((ndo, "truncated-%s - %u bytes missing!",
411				  tok2str(dccp_pkt_type_str, "", dccph_type),
412				  len - fixed_hdrlen));
413			return;
414		}
415		ND_PRINT((ndo, "%s ", tok2str(dccp_pkt_type_str, "", dccph_type)));
416		break;
417	}
418	case DCCP_PKT_CLOSEREQ:
419		fixed_hdrlen += 8;
420		if (len < fixed_hdrlen) {
421			ND_PRINT((ndo, "truncated-%s - %u bytes missing!",
422				  tok2str(dccp_pkt_type_str, "", dccph_type),
423				  len - fixed_hdrlen));
424			return;
425		}
426		ND_PRINT((ndo, "%s ", tok2str(dccp_pkt_type_str, "", dccph_type)));
427		break;
428	case DCCP_PKT_CLOSE:
429		fixed_hdrlen += 8;
430		if (len < fixed_hdrlen) {
431			ND_PRINT((ndo, "truncated-%s - %u bytes missing!",
432				  tok2str(dccp_pkt_type_str, "", dccph_type),
433				  len - fixed_hdrlen));
434			return;
435		}
436		ND_PRINT((ndo, "%s ", tok2str(dccp_pkt_type_str, "", dccph_type)));
437		break;
438	case DCCP_PKT_RESET: {
439		const struct dccp_hdr_reset *dhr =
440			(const struct dccp_hdr_reset *)(bp + fixed_hdrlen);
441		fixed_hdrlen += 12;
442		if (len < fixed_hdrlen) {
443			ND_PRINT((ndo, "truncated-%s - %u bytes missing!",
444				  tok2str(dccp_pkt_type_str, "", dccph_type),
445				  len - fixed_hdrlen));
446			return;
447		}
448		ND_TCHECK(*dhr);
449		ND_PRINT((ndo, "%s (code=%s) ",
450			  tok2str(dccp_pkt_type_str, "", dccph_type),
451			  dccp_reset_code(dhr->dccph_reset_code)));
452		break;
453	}
454	case DCCP_PKT_SYNC:
455		fixed_hdrlen += 8;
456		if (len < fixed_hdrlen) {
457			ND_PRINT((ndo, "truncated-%s - %u bytes missing!",
458				  tok2str(dccp_pkt_type_str, "", dccph_type),
459				  len - fixed_hdrlen));
460			return;
461		}
462		ND_PRINT((ndo, "%s ", tok2str(dccp_pkt_type_str, "", dccph_type)));
463		break;
464	case DCCP_PKT_SYNCACK:
465		fixed_hdrlen += 8;
466		if (len < fixed_hdrlen) {
467			ND_PRINT((ndo, "truncated-%s - %u bytes missing!",
468				  tok2str(dccp_pkt_type_str, "", dccph_type),
469				  len - fixed_hdrlen));
470			return;
471		}
472		ND_PRINT((ndo, "%s ", tok2str(dccp_pkt_type_str, "", dccph_type)));
473		break;
474	default:
475		ND_PRINT((ndo, "%s ", tok2str(dccp_pkt_type_str, "unknown-type-%u", dccph_type)));
476		break;
477	}
478
479	if ((DCCPH_TYPE(dh) != DCCP_PKT_DATA) &&
480			(DCCPH_TYPE(dh) != DCCP_PKT_REQUEST))
481		dccp_print_ack_no(ndo, bp);
482
483	if (ndo->ndo_vflag < 2)
484		return;
485
486	ND_PRINT((ndo, "seq %" PRIu64, dccp_seqno(bp)));
487
488	/* process options */
489	if (hlen > fixed_hdrlen){
490		u_int optlen;
491		cp = bp + fixed_hdrlen;
492		ND_PRINT((ndo, " <"));
493
494		hlen -= fixed_hdrlen;
495		while(1){
496			optlen = dccp_print_option(ndo, cp, hlen);
497			if (!optlen)
498				break;
499			if (hlen <= optlen)
500				break;
501			hlen -= optlen;
502			cp += optlen;
503			ND_PRINT((ndo, ", "));
504		}
505		ND_PRINT((ndo, ">"));
506	}
507	return;
508trunc:
509	ND_PRINT((ndo, "%s", tstr));
510	return;
511}
512
513static const struct tok dccp_option_values[] = {
514	{ 0, "nop" },
515	{ 1, "mandatory" },
516	{ 2, "slowreceiver" },
517	{ 32, "change_l" },
518	{ 33, "confirm_l" },
519	{ 34, "change_r" },
520	{ 35, "confirm_r" },
521	{ 36, "initcookie" },
522	{ 37, "ndp_count" },
523	{ 38, "ack_vector0" },
524	{ 39, "ack_vector1" },
525	{ 40, "data_dropped" },
526	{ 41, "timestamp" },
527	{ 42, "timestamp_echo" },
528	{ 43, "elapsed_time" },
529	{ 44, "data_checksum" },
530	{ 0, NULL }
531};
532
533static int
534dccp_print_option(netdissect_options *ndo, const u_char *option, u_int hlen)
535{
536	uint8_t optlen, i;
537
538	ND_TCHECK(*option);
539
540	if (*option >= 32) {
541		ND_TCHECK(*(option+1));
542		optlen = *(option +1);
543		if (optlen < 2) {
544			if (*option >= 128)
545				ND_PRINT((ndo, "CCID option %u optlen too short", *option));
546			else
547				ND_PRINT((ndo, "%s optlen too short",
548					  tok2str(dccp_option_values, "Option %u", *option)));
549			return 0;
550		}
551	} else
552		optlen = 1;
553
554	if (hlen < optlen) {
555		if (*option >= 128)
556			ND_PRINT((ndo, "CCID option %u optlen goes past header length",
557				  *option));
558		else
559			ND_PRINT((ndo, "%s optlen goes past header length",
560				  tok2str(dccp_option_values, "Option %u", *option)));
561		return 0;
562	}
563	ND_TCHECK2(*option, optlen);
564
565	if (*option >= 128) {
566		ND_PRINT((ndo, "CCID option %d", *option));
567		switch (optlen) {
568			case 4:
569				ND_PRINT((ndo, " %u", EXTRACT_16BITS(option + 2)));
570				break;
571			case 6:
572				ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2)));
573				break;
574			default:
575				break;
576		}
577	} else {
578		ND_PRINT((ndo, "%s", tok2str(dccp_option_values, "Option %u", *option)));
579		switch (*option) {
580		case 32:
581		case 33:
582		case 34:
583		case 35:
584			if (optlen < 3) {
585				ND_PRINT((ndo, " optlen too short"));
586				return optlen;
587			}
588			if (*(option + 2) < 10){
589				ND_PRINT((ndo, " %s", dccp_feature_nums[*(option + 2)]));
590				for (i = 0; i < optlen - 3; i++)
591					ND_PRINT((ndo, " %d", *(option + 3 + i)));
592			}
593			break;
594		case 36:
595			if (optlen > 2) {
596				ND_PRINT((ndo, " 0x"));
597				for (i = 0; i < optlen - 2; i++)
598					ND_PRINT((ndo, "%02x", *(option + 2 + i)));
599			}
600			break;
601		case 37:
602			for (i = 0; i < optlen - 2; i++)
603				ND_PRINT((ndo, " %d", *(option + 2 + i)));
604			break;
605		case 38:
606			if (optlen > 2) {
607				ND_PRINT((ndo, " 0x"));
608				for (i = 0; i < optlen - 2; i++)
609					ND_PRINT((ndo, "%02x", *(option + 2 + i)));
610			}
611			break;
612		case 39:
613			if (optlen > 2) {
614				ND_PRINT((ndo, " 0x"));
615				for (i = 0; i < optlen - 2; i++)
616					ND_PRINT((ndo, "%02x", *(option + 2 + i)));
617			}
618			break;
619		case 40:
620			if (optlen > 2) {
621				ND_PRINT((ndo, " 0x"));
622				for (i = 0; i < optlen - 2; i++)
623					ND_PRINT((ndo, "%02x", *(option + 2 + i)));
624			}
625			break;
626		case 41:
627		/*
628		 * 13.1.  Timestamp Option
629		 *
630		 *  +--------+--------+--------+--------+--------+--------+
631		 *  |00101001|00000110|          Timestamp Value          |
632		 *  +--------+--------+--------+--------+--------+--------+
633		 *   Type=41  Length=6
634		 */
635			if (optlen == 6)
636				ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2)));
637			else
638				ND_PRINT((ndo, " [optlen != 6]"));
639			break;
640		case 42:
641		/*
642		 * 13.3.  Timestamp Echo Option
643		 *
644		 *  +--------+--------+--------+--------+--------+--------+
645		 *  |00101010|00000110|           Timestamp Echo          |
646		 *  +--------+--------+--------+--------+--------+--------+
647		 *   Type=42    Len=6
648		 *
649		 *  +--------+--------+------- ... -------+--------+--------+
650		 *  |00101010|00001000|  Timestamp Echo   |   Elapsed Time  |
651		 *  +--------+--------+------- ... -------+--------+--------+
652		 *   Type=42    Len=8       (4 bytes)
653		 *
654		 *  +--------+--------+------- ... -------+------- ... -------+
655		 *  |00101010|00001010|  Timestamp Echo   |    Elapsed Time   |
656		 *  +--------+--------+------- ... -------+------- ... -------+
657		 *   Type=42   Len=10       (4 bytes)           (4 bytes)
658		 */
659			switch (optlen) {
660			case 6:
661				ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2)));
662				break;
663			case 8:
664				ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2)));
665				ND_PRINT((ndo, " (elapsed time %u)", EXTRACT_16BITS(option + 6)));
666				break;
667			case 10:
668				ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2)));
669				ND_PRINT((ndo, " (elapsed time %u)", EXTRACT_32BITS(option + 6)));
670				break;
671			default:
672				ND_PRINT((ndo, " [optlen != 6 or 8 or 10]"));
673				break;
674			}
675			break;
676		case 43:
677			if (optlen == 6)
678				ND_PRINT((ndo, " %u", EXTRACT_32BITS(option + 2)));
679			else if (optlen == 4)
680				ND_PRINT((ndo, " %u", EXTRACT_16BITS(option + 2)));
681			else
682				ND_PRINT((ndo, " [optlen != 4 or 6]"));
683			break;
684		case 44:
685			if (optlen > 2) {
686				ND_PRINT((ndo, " "));
687				for (i = 0; i < optlen - 2; i++)
688					ND_PRINT((ndo, "%02x", *(option + 2 + i)));
689			}
690			break;
691		}
692	}
693
694	return optlen;
695trunc:
696	ND_PRINT((ndo, "%s", tstr));
697	return 0;
698}
699