Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
      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  * Support for splitting captures into multiple files with a maximum
     22  * file size:
     23  *
     24  * Copyright (c) 2001
     25  *	Seth Webster <swebster (at) sst.ll.mit.edu>
     26  */
     27 
     28 #include <sys/cdefs.h>
     29 #ifndef lint
     30 __RCSID("$NetBSD: print.c,v 1.6 2024/09/02 16:15:33 christos Exp $");
     31 #endif
     32 
     33 #include <config.h>
     34 
     35 #include <stdlib.h>
     36 #include <string.h>
     37 #include <setjmp.h>
     38 
     39 #include "netdissect-stdinc.h"
     40 
     41 #include "netdissect.h"
     42 #include "addrtoname.h"
     43 #include "print.h"
     44 #include "netdissect-alloc.h"
     45 
     46 #include "pcap-missing.h"
     47 
     48 struct printer {
     49 	if_printer f;
     50 	int type;
     51 };
     52 
     53 static const struct printer printers[] = {
     54 #ifdef DLT_APPLE_IP_OVER_IEEE1394
     55 	{ ap1394_if_print,	DLT_APPLE_IP_OVER_IEEE1394 },
     56 #endif
     57 	{ arcnet_if_print,	DLT_ARCNET },
     58 #ifdef DLT_ARCNET_LINUX
     59 	{ arcnet_linux_if_print, DLT_ARCNET_LINUX },
     60 #endif
     61 	{ atm_if_print,		DLT_ATM_RFC1483 },
     62 #ifdef DLT_DSA_TAG_BRCM
     63 	{ brcm_tag_if_print,	DLT_DSA_TAG_BRCM },
     64 #endif
     65 #ifdef DLT_DSA_TAG_BRCM_PREPEND
     66 	{ brcm_tag_prepend_if_print, DLT_DSA_TAG_BRCM_PREPEND },
     67 #endif
     68 #ifdef DLT_BLUETOOTH_HCI_H4_WITH_PHDR
     69 	{ bt_if_print,		DLT_BLUETOOTH_HCI_H4_WITH_PHDR},
     70 #endif
     71 #ifdef DLT_C_HDLC
     72 	{ chdlc_if_print,	DLT_C_HDLC },
     73 #endif
     74 #ifdef DLT_HDLC
     75 	{ chdlc_if_print,	DLT_HDLC },
     76 #endif
     77 #ifdef DLT_ATM_CLIP
     78 	{ cip_if_print,		DLT_ATM_CLIP },
     79 #endif
     80 #ifdef DLT_CIP
     81 	{ cip_if_print,		DLT_CIP },
     82 #endif
     83 #ifdef DLT_DSA_TAG_DSA
     84 	{ dsa_if_print,		DLT_DSA_TAG_DSA },
     85 #endif
     86 #ifdef DLT_DSA_TAG_EDSA
     87 	{ edsa_if_print,	DLT_DSA_TAG_EDSA },
     88 #endif
     89 #ifdef DLT_ENC
     90 	{ enc_if_print,		DLT_ENC },
     91 #endif
     92 	{ ether_if_print,	DLT_EN10MB },
     93 	{ fddi_if_print,	DLT_FDDI },
     94 #ifdef DLT_FR
     95 	{ fr_if_print,		DLT_FR },
     96 #endif
     97 #ifdef DLT_FRELAY
     98 	{ fr_if_print,		DLT_FRELAY },
     99 #endif
    100 #ifdef DLT_IEEE802_11
    101 	{ ieee802_11_if_print,	DLT_IEEE802_11},
    102 #endif
    103 #ifdef DLT_IEEE802_11_RADIO_AVS
    104 	{ ieee802_11_radio_avs_if_print, DLT_IEEE802_11_RADIO_AVS },
    105 #endif
    106 #ifdef DLT_IEEE802_11_RADIO
    107 	{ ieee802_11_radio_if_print,	DLT_IEEE802_11_RADIO },
    108 #endif
    109 #ifdef DLT_IEEE802_15_4
    110 	{ ieee802_15_4_if_print, DLT_IEEE802_15_4 },
    111 #endif
    112 #ifdef DLT_IEEE802_15_4_NOFCS
    113 	{ ieee802_15_4_if_print, DLT_IEEE802_15_4_NOFCS },
    114 #endif
    115 #ifdef DLT_IEEE802_15_4_TAP
    116 	{ ieee802_15_4_tap_if_print, DLT_IEEE802_15_4_TAP },
    117 #endif
    118 #ifdef DLT_IP_OVER_FC
    119 	{ ipfc_if_print,	DLT_IP_OVER_FC },
    120 #endif
    121 #ifdef DLT_IPNET
    122 	{ ipnet_if_print,	DLT_IPNET },
    123 #endif
    124 #ifdef DLT_IPOIB
    125 	{ ipoib_if_print,       DLT_IPOIB },
    126 #endif
    127 #ifdef DLT_JUNIPER_ATM1
    128 	{ juniper_atm1_if_print, DLT_JUNIPER_ATM1 },
    129 #endif
    130 #ifdef DLT_JUNIPER_ATM2
    131 	{ juniper_atm2_if_print, DLT_JUNIPER_ATM2 },
    132 #endif
    133 #ifdef DLT_JUNIPER_CHDLC
    134 	{ juniper_chdlc_if_print,	DLT_JUNIPER_CHDLC },
    135 #endif
    136 #ifdef DLT_JUNIPER_ES
    137 	{ juniper_es_if_print,	DLT_JUNIPER_ES },
    138 #endif
    139 #ifdef DLT_JUNIPER_ETHER
    140 	{ juniper_ether_if_print,	DLT_JUNIPER_ETHER },
    141 #endif
    142 #ifdef DLT_JUNIPER_FRELAY
    143 	{ juniper_frelay_if_print,	DLT_JUNIPER_FRELAY },
    144 #endif
    145 #ifdef DLT_JUNIPER_GGSN
    146 	{ juniper_ggsn_if_print, DLT_JUNIPER_GGSN },
    147 #endif
    148 #ifdef DLT_JUNIPER_MFR
    149 	{ juniper_mfr_if_print,	DLT_JUNIPER_MFR },
    150 #endif
    151 #ifdef DLT_JUNIPER_MLFR
    152 	{ juniper_mlfr_if_print, DLT_JUNIPER_MLFR },
    153 #endif
    154 #ifdef DLT_JUNIPER_MLPPP
    155 	{ juniper_mlppp_if_print, DLT_JUNIPER_MLPPP },
    156 #endif
    157 #ifdef DLT_JUNIPER_MONITOR
    158 	{ juniper_monitor_if_print, DLT_JUNIPER_MONITOR },
    159 #endif
    160 #ifdef DLT_JUNIPER_PPP
    161 	{ juniper_ppp_if_print,	DLT_JUNIPER_PPP },
    162 #endif
    163 #ifdef DLT_JUNIPER_PPPOE_ATM
    164 	{ juniper_pppoe_atm_if_print, DLT_JUNIPER_PPPOE_ATM },
    165 #endif
    166 #ifdef DLT_JUNIPER_PPPOE
    167 	{ juniper_pppoe_if_print, DLT_JUNIPER_PPPOE },
    168 #endif
    169 #ifdef DLT_JUNIPER_SERVICES
    170 	{ juniper_services_if_print, DLT_JUNIPER_SERVICES },
    171 #endif
    172 #ifdef DLT_LTALK
    173 	{ ltalk_if_print,	DLT_LTALK },
    174 #endif
    175 #ifdef DLT_MFR
    176 	{ mfr_if_print,		DLT_MFR },
    177 #endif
    178 #ifdef DLT_NETANALYZER
    179 	{ netanalyzer_if_print, DLT_NETANALYZER },
    180 #endif
    181 #ifdef DLT_NETANALYZER_TRANSPARENT
    182 	{ netanalyzer_transparent_if_print, DLT_NETANALYZER_TRANSPARENT },
    183 #endif
    184 #ifdef DLT_NFLOG
    185 	{ nflog_if_print,	DLT_NFLOG},
    186 #endif
    187 	{ null_if_print,	DLT_NULL },
    188 #ifdef DLT_LOOP
    189 	{ null_if_print,	DLT_LOOP },
    190 #endif
    191 #ifdef DLT_PFLOG
    192 	{ pflog_if_print,	DLT_PFLOG },
    193 #endif
    194 #ifdef DLT_PKTAP
    195 	{ pktap_if_print,	DLT_PKTAP },
    196 #endif
    197 #ifdef DLT_PPI
    198 	{ ppi_if_print,		DLT_PPI },
    199 #endif
    200 #ifdef DLT_PPP_BSDOS
    201 	{ ppp_bsdos_if_print,	DLT_PPP_BSDOS },
    202 #endif
    203 #ifdef DLT_PPP_SERIAL
    204 	{ ppp_hdlc_if_print,	DLT_PPP_SERIAL },
    205 #endif
    206 	{ ppp_if_print,		DLT_PPP },
    207 #ifdef DLT_PPP_PPPD
    208 	{ ppp_if_print,		DLT_PPP_PPPD },
    209 #endif
    210 #ifdef DLT_PPP_ETHER
    211 	{ pppoe_if_print,	DLT_PPP_ETHER },
    212 #endif
    213 #ifdef DLT_PRISM_HEADER
    214 	{ prism_if_print,	DLT_PRISM_HEADER },
    215 #endif
    216 	{ raw_if_print,		DLT_RAW },
    217 #ifdef DLT_IPV4
    218 	{ raw_if_print,		DLT_IPV4 },
    219 #endif
    220 #ifdef DLT_IPV6
    221 	{ raw_if_print,		DLT_IPV6 },
    222 #endif
    223 #ifdef DLT_SLIP_BSDOS
    224 	{ sl_bsdos_if_print,	DLT_SLIP_BSDOS },
    225 #endif
    226 	{ sl_if_print,		DLT_SLIP },
    227 #ifdef DLT_LINUX_SLL
    228 	{ sll_if_print,		DLT_LINUX_SLL },
    229 #endif
    230 #ifdef DLT_LINUX_SLL2
    231 	{ sll2_if_print,	DLT_LINUX_SLL2 },
    232 #endif
    233 #ifdef DLT_SUNATM
    234 	{ sunatm_if_print,	DLT_SUNATM },
    235 #endif
    236 #ifdef DLT_SYMANTEC_FIREWALL
    237 	{ symantec_if_print,	DLT_SYMANTEC_FIREWALL },
    238 #endif
    239 	{ token_if_print,	DLT_IEEE802 },
    240 #ifdef DLT_USB_LINUX
    241 	{ usb_linux_48_byte_if_print, DLT_USB_LINUX},
    242 #endif /* DLT_USB_LINUX */
    243 #ifdef DLT_USB_LINUX_MMAPPED
    244 	{ usb_linux_64_byte_if_print, DLT_USB_LINUX_MMAPPED},
    245 #endif /* DLT_USB_LINUX_MMAPPED */
    246 #ifdef DLT_VSOCK
    247 	{ vsock_if_print,	DLT_VSOCK },
    248 #endif
    249 #ifdef DLT_PFSYNC
    250         { pfsync_if_print,	DLT_PFSYNC },
    251 #endif
    252 	{ NULL,			0 },
    253 };
    254 
    255 static void	ndo_default_print(netdissect_options *ndo, const u_char *bp,
    256 		    u_int length);
    257 
    258 static void NORETURN ndo_error(netdissect_options *ndo,
    259 		     status_exit_codes_t status,
    260 		     FORMAT_STRING(const char *fmt), ...)
    261 		     PRINTFLIKE(3, 4);
    262 static void	ndo_warning(netdissect_options *ndo,
    263 		    FORMAT_STRING(const char *fmt), ...)
    264 		    PRINTFLIKE(2, 3);
    265 
    266 static int	ndo_printf(netdissect_options *ndo,
    267 		     FORMAT_STRING(const char *fmt), ...)
    268 		     PRINTFLIKE(2, 3);
    269 
    270 void
    271 init_print(netdissect_options *ndo, uint32_t localnet, uint32_t mask)
    272 {
    273 	init_addrtoname(ndo, localnet, mask);
    274 }
    275 
    276 if_printer
    277 lookup_printer(int type)
    278 {
    279 	const struct printer *p;
    280 
    281 	for (p = printers; p->f; ++p)
    282 		if (type == p->type)
    283 			return p->f;
    284 
    285 #if defined(DLT_USER2) && defined(DLT_PKTAP)
    286 	/*
    287 	 * Apple incorrectly chose to use DLT_USER2 for their PKTAP
    288 	 * header.
    289 	 *
    290 	 * We map DLT_PKTAP, whether it's DLT_USER2 as it is on Darwin-
    291 	 * based OSes or the same value as LINKTYPE_PKTAP as it is on
    292 	 * other OSes, to LINKTYPE_PKTAP, so files written with
    293 	 * this version of libpcap for a DLT_PKTAP capture have a link-
    294 	 * layer header type of LINKTYPE_PKTAP.
    295 	 *
    296 	 * However, files written on OS X Mavericks for a DLT_PKTAP
    297 	 * capture have a link-layer header type of LINKTYPE_USER2.
    298 	 * If we don't have a printer for DLT_USER2, and type is
    299 	 * DLT_USER2, we look up the printer for DLT_PKTAP and use
    300 	 * that.
    301 	 */
    302 	if (type == DLT_USER2) {
    303 		for (p = printers; p->f; ++p)
    304 			if (DLT_PKTAP == p->type)
    305 				return p->f;
    306 	}
    307 #endif
    308 
    309 	return NULL;
    310 	/* NOTREACHED */
    311 }
    312 
    313 int
    314 has_printer(int type)
    315 {
    316 	return (lookup_printer(type) != NULL);
    317 }
    318 
    319 if_printer
    320 get_if_printer(int type)
    321 {
    322 	if_printer printer;
    323 
    324 	printer = lookup_printer(type);
    325 	if (printer == NULL)
    326 		printer = unsupported_if_print;
    327 	return printer;
    328 }
    329 
    330 #ifdef ENABLE_INSTRUMENT_FUNCTIONS
    331 extern int profile_func_level;
    332 static int pretty_print_packet_level = -1;
    333 #endif
    334 
    335 void
    336 pretty_print_packet(netdissect_options *ndo, const struct pcap_pkthdr *h,
    337 		    const u_char *sp, u_int packets_captured)
    338 {
    339 	u_int hdrlen = 0;
    340 	int invalid_header = 0;
    341 
    342 #ifdef ENABLE_INSTRUMENT_FUNCTIONS
    343 	if (pretty_print_packet_level == -1)
    344 		pretty_print_packet_level = profile_func_level;
    345 #endif
    346 
    347 	if (ndo->ndo_packet_number)
    348 		ND_PRINT("%5u  ", packets_captured);
    349 
    350 	/* Sanity checks on packet length / capture length */
    351 	if (h->caplen == 0) {
    352 		invalid_header = 1;
    353 		ND_PRINT("[Invalid header: caplen==0");
    354 	}
    355 	if (h->len == 0) {
    356 		if (!invalid_header) {
    357 			invalid_header = 1;
    358 			ND_PRINT("[Invalid header:");
    359 		} else
    360 			ND_PRINT(",");
    361 		ND_PRINT(" len==0");
    362 	} else if (h->len < h->caplen) {
    363 		if (!invalid_header) {
    364 			invalid_header = 1;
    365 			ND_PRINT("[Invalid header:");
    366 		} else
    367 			ND_PRINT(",");
    368 		ND_PRINT(" len(%u) < caplen(%u)", h->len, h->caplen);
    369 	}
    370 	if (h->caplen > MAXIMUM_SNAPLEN) {
    371 		if (!invalid_header) {
    372 			invalid_header = 1;
    373 			ND_PRINT("[Invalid header:");
    374 		} else
    375 			ND_PRINT(",");
    376 		ND_PRINT(" caplen(%u) > %u", h->caplen, MAXIMUM_SNAPLEN);
    377 	}
    378 	if (h->len > MAXIMUM_SNAPLEN) {
    379 		if (!invalid_header) {
    380 			invalid_header = 1;
    381 			ND_PRINT("[Invalid header:");
    382 		} else
    383 			ND_PRINT(",");
    384 		ND_PRINT(" len(%u) > %u", h->len, MAXIMUM_SNAPLEN);
    385 	}
    386 	if (invalid_header) {
    387 		ND_PRINT("]\n");
    388 		return;
    389 	}
    390 
    391 	/*
    392 	 * At this point:
    393 	 *   capture length != 0,
    394 	 *   packet length != 0,
    395 	 *   capture length <= MAXIMUM_SNAPLEN,
    396 	 *   packet length <= MAXIMUM_SNAPLEN,
    397 	 *   packet length >= capture length.
    398 	 *
    399 	 * Currently, there is no D-Bus printer, thus no need for
    400 	 * bigger lengths.
    401 	 */
    402 
    403 	/*
    404 	 * The header /usr/include/pcap/pcap.h in OpenBSD declares h->ts as
    405 	 * struct bpf_timeval, not struct timeval. The former comes from
    406 	 * /usr/include/net/bpf.h and uses 32-bit unsigned types instead of
    407 	 * the types used in struct timeval.
    408 	 */
    409 	struct timeval tvbuf;
    410 	tvbuf.tv_sec = h->ts.tv_sec;
    411 	tvbuf.tv_usec = h->ts.tv_usec;
    412 	ts_print(ndo, &tvbuf);
    413 
    414 	/*
    415 	 * Printers must check that they're not walking off the end of
    416 	 * the packet.
    417 	 * Rather than pass it all the way down, we set this member
    418 	 * of the netdissect_options structure.
    419 	 */
    420 	ndo->ndo_snapend = sp + h->caplen;
    421 	ndo->ndo_packetp = sp;
    422 
    423 	ndo->ndo_protocol = "";
    424 	ndo->ndo_ll_hdr_len = 0;
    425 	switch (setjmp(ndo->ndo_early_end)) {
    426 	case 0:
    427 		/* Print the packet. */
    428 		(ndo->ndo_if_printer)(ndo, h, sp);
    429 		break;
    430 	case ND_TRUNCATED:
    431 		/* A printer quit because the packet was truncated; report it */
    432 		nd_print_trunc(ndo);
    433 		/* Print the full packet */
    434 		ndo->ndo_ll_hdr_len = 0;
    435 #ifdef ENABLE_INSTRUMENT_FUNCTIONS
    436 		/* truncation => reassignment */
    437 		profile_func_level = pretty_print_packet_level;
    438 #endif
    439 		break;
    440 	}
    441 	hdrlen = ndo->ndo_ll_hdr_len;
    442 
    443 	/*
    444 	 * Empty the stack of packet information, freeing all pushed buffers;
    445 	 * if we got here by a printer quitting, we need to release anything
    446 	 * that didn't get released because we longjmped out of the code
    447 	 * before it popped the packet information.
    448 	 */
    449 	nd_pop_all_packet_info(ndo);
    450 
    451 	/*
    452 	 * Restore the originals snapend and packetp, as a printer
    453 	 * might have changed them.
    454 	 *
    455 	 * XXX - nd_pop_all_packet_info() should have restored the
    456 	 * original values, but, just in case....
    457 	 */
    458 	ndo->ndo_snapend = sp + h->caplen;
    459 	ndo->ndo_packetp = sp;
    460 	if (ndo->ndo_Xflag) {
    461 		/*
    462 		 * Print the raw packet data in hex and ASCII.
    463 		 */
    464 		if (ndo->ndo_Xflag > 1) {
    465 			/*
    466 			 * Include the link-layer header.
    467 			 */
    468 			hex_and_ascii_print(ndo, "\n\t", sp, h->caplen);
    469 		} else {
    470 			/*
    471 			 * Don't include the link-layer header - and if
    472 			 * we have nothing past the link-layer header,
    473 			 * print nothing.
    474 			 */
    475 			if (h->caplen > hdrlen)
    476 				hex_and_ascii_print(ndo, "\n\t", sp + hdrlen,
    477 						    h->caplen - hdrlen);
    478 		}
    479 	} else if (ndo->ndo_xflag) {
    480 		/*
    481 		 * Print the raw packet data in hex.
    482 		 */
    483 		if (ndo->ndo_xflag > 1) {
    484 			/*
    485 			 * Include the link-layer header.
    486 			 */
    487 			hex_print(ndo, "\n\t", sp, h->caplen);
    488 		} else {
    489 			/*
    490 			 * Don't include the link-layer header - and if
    491 			 * we have nothing past the link-layer header,
    492 			 * print nothing.
    493 			 */
    494 			if (h->caplen > hdrlen)
    495 				hex_print(ndo, "\n\t", sp + hdrlen,
    496 					  h->caplen - hdrlen);
    497 		}
    498 	} else if (ndo->ndo_Aflag) {
    499 		/*
    500 		 * Print the raw packet data in ASCII.
    501 		 */
    502 		if (ndo->ndo_Aflag > 1) {
    503 			/*
    504 			 * Include the link-layer header.
    505 			 */
    506 			ascii_print(ndo, sp, h->caplen);
    507 		} else {
    508 			/*
    509 			 * Don't include the link-layer header - and if
    510 			 * we have nothing past the link-layer header,
    511 			 * print nothing.
    512 			 */
    513 			if (h->caplen > hdrlen)
    514 				ascii_print(ndo, sp + hdrlen, h->caplen - hdrlen);
    515 		}
    516 	}
    517 
    518 	ND_PRINT("\n");
    519 	nd_free_all(ndo);
    520 }
    521 
    522 /*
    523  * By default, print the specified data out in hex and ASCII.
    524  */
    525 static void
    526 ndo_default_print(netdissect_options *ndo, const u_char *bp, u_int length)
    527 {
    528 	hex_and_ascii_print(ndo, "\n\t", bp, length); /* pass on lf and indentation string */
    529 }
    530 
    531 /* VARARGS */
    532 static void
    533 ndo_error(netdissect_options *ndo, status_exit_codes_t status,
    534 	  const char *fmt, ...)
    535 {
    536 	va_list ap;
    537 
    538 	if (ndo->program_name)
    539 		(void)fprintf(stderr, "%s: ", ndo->program_name);
    540 	va_start(ap, fmt);
    541 	(void)vfprintf(stderr, fmt, ap);
    542 	va_end(ap);
    543 	if (*fmt) {
    544 		fmt += strlen(fmt);
    545 		if (fmt[-1] != '\n')
    546 			(void)fputc('\n', stderr);
    547 	}
    548 	nd_cleanup();
    549 	exit(status);
    550 	/* NOTREACHED */
    551 }
    552 
    553 /* VARARGS */
    554 static void
    555 ndo_warning(netdissect_options *ndo, const char *fmt, ...)
    556 {
    557 	va_list ap;
    558 
    559 	if (ndo->program_name)
    560 		(void)fprintf(stderr, "%s: ", ndo->program_name);
    561 	(void)fprintf(stderr, "WARNING: ");
    562 	va_start(ap, fmt);
    563 	(void)vfprintf(stderr, fmt, ap);
    564 	va_end(ap);
    565 	if (*fmt) {
    566 		fmt += strlen(fmt);
    567 		if (fmt[-1] != '\n')
    568 			(void)fputc('\n', stderr);
    569 	}
    570 }
    571 
    572 static int
    573 ndo_printf(netdissect_options *ndo, const char *fmt, ...)
    574 {
    575 	va_list args;
    576 	int ret;
    577 
    578 	va_start(args, fmt);
    579 	ret = vfprintf(stdout, fmt, args);
    580 	va_end(args);
    581 
    582 	if (ret < 0)
    583 		ndo_error(ndo, S_ERR_ND_WRITE_FILE,
    584 			  "Unable to write output: %s", pcap_strerror(errno));
    585 	return (ret);
    586 }
    587 
    588 void
    589 ndo_set_function_pointers(netdissect_options *ndo)
    590 {
    591 	ndo->ndo_default_print=ndo_default_print;
    592 	ndo->ndo_printf=ndo_printf;
    593 	ndo->ndo_error=ndo_error;
    594 	ndo->ndo_warning=ndo_warning;
    595 }
    596