]> The Tcpdump Group git mirrors - tcpdump/blob - print-ip.c
Remove useless comments
[tcpdump] / print-ip.c
1 /*
2 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22 /* \summary: IP printer */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include "netdissect-stdinc.h"
29
30 #include <string.h>
31
32 #include "netdissect.h"
33 #include "addrtoname.h"
34 #include "extract.h"
35
36 #include "ip.h"
37 #include "ipproto.h"
38
39 static const char tstr[] = "[|ip]";
40
41 static const struct tok ip_option_values[] = {
42 { IPOPT_EOL, "EOL" },
43 { IPOPT_NOP, "NOP" },
44 { IPOPT_TS, "timestamp" },
45 { IPOPT_SECURITY, "security" },
46 { IPOPT_RR, "RR" },
47 { IPOPT_SSRR, "SSRR" },
48 { IPOPT_LSRR, "LSRR" },
49 { IPOPT_RA, "RA" },
50 { IPOPT_RFC1393, "traceroute" },
51 { 0, NULL }
52 };
53
54 /*
55 * print the recorded route in an IP RR, LSRR or SSRR option.
56 */
57 static int
58 ip_printroute(netdissect_options *ndo,
59 const u_char *cp, u_int length)
60 {
61 u_int ptr;
62 u_int len;
63
64 if (length < 3) {
65 ND_PRINT(" [bad length %u]", length);
66 return (0);
67 }
68 if ((length + 1) & 3)
69 ND_PRINT(" [bad length %u]", length);
70 ND_TCHECK_1(cp + 2);
71 ptr = EXTRACT_U_1(cp + 2) - 1;
72 if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)
73 ND_PRINT(" [bad ptr %u]", EXTRACT_U_1(cp + 2));
74
75 for (len = 3; len < length; len += 4) {
76 ND_TCHECK_4(cp + len);
77 ND_PRINT(" %s", ipaddr_string(ndo, cp + len));
78 if (ptr > len)
79 ND_PRINT(",");
80 }
81 return (0);
82
83 trunc:
84 return (-1);
85 }
86
87 /*
88 * If source-routing is present and valid, return the final destination.
89 * Otherwise, return IP destination.
90 *
91 * This is used for UDP and TCP pseudo-header in the checksum
92 * calculation.
93 */
94 static uint32_t
95 ip_finddst(netdissect_options *ndo,
96 const struct ip *ip)
97 {
98 u_int length;
99 u_int len;
100 const u_char *cp;
101
102 cp = (const u_char *)(ip + 1);
103 length = (IP_HL(ip) << 2);
104 if (length < sizeof(struct ip))
105 goto trunc;
106 length -= sizeof(struct ip);
107
108 for (; length != 0; cp += len, length -= len) {
109 int tt;
110
111 ND_TCHECK_1(cp);
112 tt = EXTRACT_U_1(cp);
113 if (tt == IPOPT_EOL)
114 break;
115 else if (tt == IPOPT_NOP)
116 len = 1;
117 else {
118 ND_TCHECK_1(cp + 1);
119 len = EXTRACT_U_1(cp + 1);
120 if (len < 2)
121 break;
122 }
123 if (length < len)
124 goto trunc;
125 ND_TCHECK_LEN(cp, len);
126 switch (tt) {
127
128 case IPOPT_SSRR:
129 case IPOPT_LSRR:
130 if (len < 7)
131 break;
132 return (EXTRACT_IPV4_TO_NETWORK_ORDER(cp + len - 4));
133 }
134 }
135 trunc:
136 return (EXTRACT_IPV4_TO_NETWORK_ORDER(ip->ip_dst));
137 }
138
139 /*
140 * Compute a V4-style checksum by building a pseudoheader.
141 */
142 int
143 nextproto4_cksum(netdissect_options *ndo,
144 const struct ip *ip, const uint8_t *data,
145 u_int len, u_int covlen, u_int next_proto)
146 {
147 struct phdr {
148 uint32_t src;
149 uint32_t dst;
150 u_char mbz;
151 u_char proto;
152 uint16_t len;
153 } ph;
154 struct cksum_vec vec[2];
155
156 /* pseudo-header.. */
157 ph.len = htons((uint16_t)len);
158 ph.mbz = 0;
159 ph.proto = next_proto;
160 ph.src = EXTRACT_IPV4_TO_NETWORK_ORDER(ip->ip_src);
161 if (IP_HL(ip) == 5)
162 ph.dst = EXTRACT_IPV4_TO_NETWORK_ORDER(ip->ip_dst);
163 else
164 ph.dst = ip_finddst(ndo, ip);
165
166 vec[0].ptr = (const uint8_t *)(void *)&ph;
167 vec[0].len = sizeof(ph);
168 vec[1].ptr = data;
169 vec[1].len = covlen;
170 return (in_cksum(vec, 2));
171 }
172
173 static int
174 ip_printts(netdissect_options *ndo,
175 const u_char *cp, u_int length)
176 {
177 u_int ptr;
178 u_int len;
179 u_int hoplen;
180 const char *type;
181
182 if (length < 4) {
183 ND_PRINT("[bad length %u]", length);
184 return (0);
185 }
186 ND_PRINT(" TS{");
187 ND_TCHECK_1(cp + 3);
188 hoplen = ((EXTRACT_U_1(cp + 3) & 0xF) != IPOPT_TS_TSONLY) ? 8 : 4;
189 if ((length - 4) & (hoplen-1))
190 ND_PRINT("[bad length %u]", length);
191 ND_TCHECK_1(cp + 2);
192 ptr = EXTRACT_U_1(cp + 2) - 1;
193 len = 0;
194 if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1)
195 ND_PRINT("[bad ptr %u]", EXTRACT_U_1(cp + 2));
196 ND_TCHECK_1(cp + 3);
197 switch (EXTRACT_U_1(cp + 3)&0xF) {
198 case IPOPT_TS_TSONLY:
199 ND_PRINT("TSONLY");
200 break;
201 case IPOPT_TS_TSANDADDR:
202 ND_PRINT("TS+ADDR");
203 break;
204 /*
205 * prespecified should really be 3, but some ones might send 2
206 * instead, and the IPOPT_TS_PRESPEC constant can apparently
207 * have both values, so we have to hard-code it here.
208 */
209
210 case 2:
211 ND_PRINT("PRESPEC2.0");
212 break;
213 case 3: /* IPOPT_TS_PRESPEC */
214 ND_PRINT("PRESPEC");
215 break;
216 default:
217 ND_PRINT("[bad ts type %u]", EXTRACT_U_1(cp + 3)&0xF);
218 goto done;
219 }
220
221 type = " ";
222 for (len = 4; len < length; len += hoplen) {
223 if (ptr == len)
224 type = " ^ ";
225 ND_TCHECK_LEN(cp + len, hoplen);
226 ND_PRINT("%s%u@%s", type, EXTRACT_BE_U_4(cp + len + hoplen - 4),
227 hoplen!=8 ? "" : ipaddr_string(ndo, cp + len));
228 type = " ";
229 }
230
231 done:
232 ND_PRINT("%s", ptr == len ? " ^ " : "");
233
234 if (EXTRACT_U_1(cp + 3) >> 4)
235 ND_PRINT(" [%u hops not recorded]} ", EXTRACT_U_1(cp + 3)>>4);
236 else
237 ND_PRINT("}");
238 return (0);
239
240 trunc:
241 return (-1);
242 }
243
244 /*
245 * print IP options.
246 */
247 static void
248 ip_optprint(netdissect_options *ndo,
249 const u_char *cp, u_int length)
250 {
251 u_int option_len;
252 const char *sep = "";
253
254 for (; length > 0; cp += option_len, length -= option_len) {
255 u_int option_code;
256
257 ND_PRINT("%s", sep);
258 sep = ",";
259
260 ND_TCHECK_1(cp);
261 option_code = EXTRACT_U_1(cp);
262
263 ND_PRINT("%s",
264 tok2str(ip_option_values,"unknown %u",option_code));
265
266 if (option_code == IPOPT_NOP ||
267 option_code == IPOPT_EOL)
268 option_len = 1;
269
270 else {
271 ND_TCHECK_1(cp + 1);
272 option_len = EXTRACT_U_1(cp + 1);
273 if (option_len < 2) {
274 ND_PRINT(" [bad length %u]", option_len);
275 return;
276 }
277 }
278
279 if (option_len > length) {
280 ND_PRINT(" [bad length %u]", option_len);
281 return;
282 }
283
284 ND_TCHECK_LEN(cp, option_len);
285
286 switch (option_code) {
287 case IPOPT_EOL:
288 return;
289
290 case IPOPT_TS:
291 if (ip_printts(ndo, cp, option_len) == -1)
292 goto trunc;
293 break;
294
295 case IPOPT_RR: /* fall through */
296 case IPOPT_SSRR:
297 case IPOPT_LSRR:
298 if (ip_printroute(ndo, cp, option_len) == -1)
299 goto trunc;
300 break;
301
302 case IPOPT_RA:
303 if (option_len < 4) {
304 ND_PRINT(" [bad length %u]", option_len);
305 break;
306 }
307 ND_TCHECK_1(cp + 3);
308 if (EXTRACT_BE_U_2(cp + 2) != 0)
309 ND_PRINT(" value %u", EXTRACT_BE_U_2(cp + 2));
310 break;
311
312 case IPOPT_NOP: /* nothing to print - fall through */
313 case IPOPT_SECURITY:
314 default:
315 break;
316 }
317 }
318 return;
319
320 trunc:
321 ND_PRINT("%s", tstr);
322 }
323
324 #define IP_RES 0x8000
325
326 static const struct tok ip_frag_values[] = {
327 { IP_MF, "+" },
328 { IP_DF, "DF" },
329 { IP_RES, "rsvd" }, /* The RFC3514 evil ;-) bit */
330 { 0, NULL }
331 };
332
333 struct ip_print_demux_state {
334 const struct ip *ip;
335 const u_char *cp;
336 u_int len, off;
337 u_char nh;
338 int advance;
339 };
340
341 static void
342 ip_print_demux(netdissect_options *ndo,
343 struct ip_print_demux_state *ipds)
344 {
345 const char *p_name;
346
347 again:
348 switch (ipds->nh) {
349
350 case IPPROTO_AH:
351 if (!ND_TTEST_1(ipds->cp)) {
352 ND_PRINT("[|AH]");
353 break;
354 }
355 ipds->nh = EXTRACT_U_1(ipds->cp);
356 ipds->advance = ah_print(ndo, ipds->cp);
357 if (ipds->advance <= 0)
358 break;
359 ipds->cp += ipds->advance;
360 ipds->len -= ipds->advance;
361 goto again;
362
363 case IPPROTO_ESP:
364 {
365 u_int enh, padlen;
366 ipds->advance = esp_print(ndo, ipds->cp, ipds->len,
367 (const u_char *)ipds->ip,
368 &enh, &padlen);
369 if (ipds->advance <= 0)
370 break;
371 ipds->cp += ipds->advance;
372 ipds->len -= ipds->advance + padlen;
373 ipds->nh = enh & 0xff;
374 goto again;
375 }
376
377 case IPPROTO_IPCOMP:
378 {
379 ipcomp_print(ndo, ipds->cp);
380 /*
381 * Either this has decompressed the payload and
382 * printed it, in which case there's nothing more
383 * to do, or it hasn't, in which case there's
384 * nothing more to do.
385 */
386 break;
387 }
388
389 case IPPROTO_SCTP:
390 sctp_print(ndo, ipds->cp, (const u_char *)ipds->ip, ipds->len);
391 break;
392
393 case IPPROTO_DCCP:
394 dccp_print(ndo, ipds->cp, (const u_char *)ipds->ip, ipds->len);
395 break;
396
397 case IPPROTO_TCP:
398 /* pass on the MF bit plus the offset to detect fragments */
399 tcp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip,
400 ipds->off & (IP_MF|IP_OFFMASK));
401 break;
402
403 case IPPROTO_UDP:
404 /* pass on the MF bit plus the offset to detect fragments */
405 udp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip,
406 ipds->off & (IP_MF|IP_OFFMASK));
407 break;
408
409 case IPPROTO_ICMP:
410 /* pass on the MF bit plus the offset to detect fragments */
411 icmp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip,
412 ipds->off & (IP_MF|IP_OFFMASK));
413 break;
414
415 case IPPROTO_PIGP:
416 /*
417 * XXX - the current IANA protocol number assignments
418 * page lists 9 as "any private interior gateway
419 * (used by Cisco for their IGRP)" and 88 as
420 * "EIGRP" from Cisco.
421 *
422 * Recent BSD <netinet/in.h> headers define
423 * IP_PROTO_PIGP as 9 and IP_PROTO_IGRP as 88.
424 * We define IP_PROTO_PIGP as 9 and
425 * IP_PROTO_EIGRP as 88; those names better
426 * match was the current protocol number
427 * assignments say.
428 */
429 igrp_print(ndo, ipds->cp, ipds->len);
430 break;
431
432 case IPPROTO_EIGRP:
433 eigrp_print(ndo, ipds->cp, ipds->len);
434 break;
435
436 case IPPROTO_ND:
437 ND_PRINT(" nd %u", ipds->len);
438 break;
439
440 case IPPROTO_EGP:
441 egp_print(ndo, ipds->cp, ipds->len);
442 break;
443
444 case IPPROTO_OSPF:
445 ospf_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip);
446 break;
447
448 case IPPROTO_IGMP:
449 igmp_print(ndo, ipds->cp, ipds->len);
450 break;
451
452 case IPPROTO_IPV4:
453 /* DVMRP multicast tunnel (ip-in-ip encapsulation) */
454 ip_print(ndo, ipds->cp, ipds->len);
455 if (! ndo->ndo_vflag) {
456 ND_PRINT(" (ipip-proto-4)");
457 return;
458 }
459 break;
460
461 case IPPROTO_IPV6:
462 /* ip6-in-ip encapsulation */
463 ip6_print(ndo, ipds->cp, ipds->len);
464 break;
465
466 case IPPROTO_RSVP:
467 rsvp_print(ndo, ipds->cp, ipds->len);
468 break;
469
470 case IPPROTO_GRE:
471 /* do it */
472 gre_print(ndo, ipds->cp, ipds->len);
473 break;
474
475 case IPPROTO_MOBILE:
476 mobile_print(ndo, ipds->cp, ipds->len);
477 break;
478
479 case IPPROTO_PIM:
480 pim_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip);
481 break;
482
483 case IPPROTO_VRRP:
484 if (ndo->ndo_packettype == PT_CARP) {
485 if (ndo->ndo_vflag)
486 ND_PRINT("carp %s > %s: ",
487 ipaddr_string(ndo, ipds->ip->ip_src),
488 ipaddr_string(ndo, ipds->ip->ip_dst));
489 carp_print(ndo, ipds->cp, ipds->len,
490 EXTRACT_U_1(ipds->ip->ip_ttl));
491 } else {
492 if (ndo->ndo_vflag)
493 ND_PRINT("vrrp %s > %s: ",
494 ipaddr_string(ndo, ipds->ip->ip_src),
495 ipaddr_string(ndo, ipds->ip->ip_dst));
496 vrrp_print(ndo, ipds->cp, ipds->len,
497 (const u_char *)ipds->ip,
498 EXTRACT_U_1(ipds->ip->ip_ttl));
499 }
500 break;
501
502 case IPPROTO_PGM:
503 pgm_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip);
504 break;
505
506 default:
507 if (ndo->ndo_nflag==0 && (p_name = netdb_protoname(ipds->nh)) != NULL)
508 ND_PRINT(" %s", p_name);
509 else
510 ND_PRINT(" ip-proto-%u", ipds->nh);
511 ND_PRINT(" %u", ipds->len);
512 break;
513 }
514 }
515
516 void
517 ip_inner_print(netdissect_options *ndo,
518 const u_char *bp,
519 u_int length, u_int nh,
520 const u_char *bp2)
521 {
522 struct ip_print_demux_state ipd;
523
524 ipd.ip = (const struct ip *)bp2;
525 ipd.cp = bp;
526 ipd.len = length;
527 ipd.off = 0;
528 ipd.nh = nh;
529 ipd.advance = 0;
530
531 ip_print_demux(ndo, &ipd);
532 }
533
534
535 /*
536 * print an IP datagram.
537 */
538 void
539 ip_print(netdissect_options *ndo,
540 const u_char *bp,
541 u_int length)
542 {
543 struct ip_print_demux_state ipd;
544 struct ip_print_demux_state *ipds=&ipd;
545 const u_char *ipend;
546 u_int hlen;
547 struct cksum_vec vec[1];
548 uint8_t ip_tos, ip_ttl, ip_proto;
549 uint16_t sum, ip_sum;
550 const char *p_name;
551
552 ndo->ndo_protocol = "ip";
553 ipds->ip = (const struct ip *)bp;
554 ND_TCHECK_1(ipds->ip->ip_vhl);
555 if (IP_V(ipds->ip) != 4) { /* print version and fail if != 4 */
556 if (IP_V(ipds->ip) == 6)
557 ND_PRINT("IP6, wrong link-layer encapsulation");
558 else
559 ND_PRINT("IP%u", IP_V(ipds->ip));
560 return;
561 }
562 if (!ndo->ndo_eflag)
563 ND_PRINT("IP ");
564
565 ND_TCHECK_SIZE(ipds->ip);
566 if (length < sizeof (struct ip)) {
567 ND_PRINT("truncated-ip %u", length);
568 return;
569 }
570 hlen = IP_HL(ipds->ip) * 4;
571 if (hlen < sizeof (struct ip)) {
572 ND_PRINT("bad-hlen %u", hlen);
573 return;
574 }
575
576 ipds->len = EXTRACT_BE_U_2(ipds->ip->ip_len);
577 if (length < ipds->len)
578 ND_PRINT("truncated-ip - %u bytes missing! ",
579 ipds->len - length);
580 if (ipds->len < hlen) {
581 #ifdef GUESS_TSO
582 if (ipds->len) {
583 ND_PRINT("bad-len %u", ipds->len);
584 return;
585 }
586 else {
587 /* we guess that it is a TSO send */
588 ipds->len = length;
589 }
590 #else
591 ND_PRINT("bad-len %u", ipds->len);
592 return;
593 #endif /* GUESS_TSO */
594 }
595
596 /*
597 * Cut off the snapshot length to the end of the IP payload.
598 */
599 ipend = bp + ipds->len;
600 if (ipend < ndo->ndo_snapend)
601 ndo->ndo_snapend = ipend;
602
603 ipds->len -= hlen;
604
605 ipds->off = EXTRACT_BE_U_2(ipds->ip->ip_off);
606
607 ip_proto = EXTRACT_U_1(ipds->ip->ip_p);
608
609 if (ndo->ndo_vflag) {
610 ip_tos = EXTRACT_U_1(ipds->ip->ip_tos);
611 ND_PRINT("(tos 0x%x", ip_tos);
612 /* ECN bits */
613 switch (ip_tos & 0x03) {
614
615 case 0:
616 break;
617
618 case 1:
619 ND_PRINT(",ECT(1)");
620 break;
621
622 case 2:
623 ND_PRINT(",ECT(0)");
624 break;
625
626 case 3:
627 ND_PRINT(",CE");
628 break;
629 }
630
631 ip_ttl = EXTRACT_U_1(ipds->ip->ip_ttl);
632 if (ip_ttl >= 1)
633 ND_PRINT(", ttl %u", ip_ttl);
634
635 /*
636 * for the firewall guys, print id, offset.
637 * On all but the last stick a "+" in the flags portion.
638 * For unfragmented datagrams, note the don't fragment flag.
639 */
640 ND_PRINT(", id %u, offset %u, flags [%s], proto %s (%u)",
641 EXTRACT_BE_U_2(ipds->ip->ip_id),
642 (ipds->off & 0x1fff) * 8,
643 bittok2str(ip_frag_values, "none", ipds->off&0xe000),
644 tok2str(ipproto_values, "unknown", ip_proto),
645 ip_proto);
646
647 ND_PRINT(", length %u", EXTRACT_BE_U_2(ipds->ip->ip_len));
648
649 if ((hlen - sizeof(struct ip)) > 0) {
650 ND_PRINT(", options (");
651 ip_optprint(ndo, (const u_char *)(ipds->ip + 1), hlen - sizeof(struct ip));
652 ND_PRINT(")");
653 }
654
655 if (!ndo->ndo_Kflag && (const u_char *)ipds->ip + hlen <= ndo->ndo_snapend) {
656 vec[0].ptr = (const uint8_t *)(const void *)ipds->ip;
657 vec[0].len = hlen;
658 sum = in_cksum(vec, 1);
659 if (sum != 0) {
660 ip_sum = EXTRACT_BE_U_2(ipds->ip->ip_sum);
661 ND_PRINT(", bad cksum %x (->%x)!", ip_sum,
662 in_cksum_shouldbe(ip_sum, sum));
663 }
664 }
665
666 ND_PRINT(")\n ");
667 }
668
669 /*
670 * If this is fragment zero, hand it to the next higher
671 * level protocol.
672 */
673 if ((ipds->off & 0x1fff) == 0) {
674 ipds->cp = (const u_char *)ipds->ip + hlen;
675 ipds->nh = EXTRACT_U_1(ipds->ip->ip_p);
676
677 if (ipds->nh != IPPROTO_TCP && ipds->nh != IPPROTO_UDP &&
678 ipds->nh != IPPROTO_SCTP && ipds->nh != IPPROTO_DCCP) {
679 ND_PRINT("%s > %s: ",
680 ipaddr_string(ndo, ipds->ip->ip_src),
681 ipaddr_string(ndo, ipds->ip->ip_dst));
682 }
683 ip_print_demux(ndo, ipds);
684 } else {
685 /*
686 * Ultra quiet now means that all this stuff should be
687 * suppressed.
688 */
689 if (ndo->ndo_qflag > 1)
690 return;
691
692 /*
693 * This isn't the first frag, so we're missing the
694 * next level protocol header. print the ip addr
695 * and the protocol.
696 */
697 ND_PRINT("%s > %s:", ipaddr_string(ndo, ipds->ip->ip_src),
698 ipaddr_string(ndo, ipds->ip->ip_dst));
699 if (!ndo->ndo_nflag && (p_name = netdb_protoname(ip_proto)) != NULL)
700 ND_PRINT(" %s", p_name);
701 else
702 ND_PRINT(" ip-proto-%u", ip_proto);
703 }
704 return;
705
706 trunc:
707 ND_PRINT("%s", tstr);
708 return;
709 }
710
711 void
712 ipN_print(netdissect_options *ndo, const u_char *bp, u_int length)
713 {
714 ndo->ndo_protocol = "ipN";
715 if (length < 1) {
716 ND_PRINT("truncated-ip %u", length);
717 return;
718 }
719
720 ND_TCHECK_1(bp);
721 switch (EXTRACT_U_1(bp) & 0xF0) {
722 case 0x40:
723 ip_print (ndo, bp, length);
724 break;
725 case 0x60:
726 ip6_print (ndo, bp, length);
727 break;
728 default:
729 ND_PRINT("unknown ip %u", (EXTRACT_U_1(bp) & 0xF0) >> 4);
730 break;
731 }
732 return;
733
734 trunc:
735 ND_PRINT("%s", tstr);
736 return;
737 }