]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print.c
gre: add support for MikroTik Ethernet-over-IP hack.
[tcpdump] / print.c
diff --git a/print.c b/print.c
index fb62e15c202880ea90b2e41275bffcf9034df760..123c842c2d8de2fa63485770eb300b53e407444f 100644 (file)
--- a/print.c
+++ b/print.c
  */
 
 #ifdef HAVE_CONFIG_H
-#include "config.h"
+#include <config.h>
 #endif
 
 #include <stdlib.h>
 #include <string.h>
+#include <setjmp.h>
 
-#include <netdissect-stdinc.h>
+#include "netdissect-stdinc.h"
 
 #include "netdissect.h"
 #include "addrtoname.h"
 #include "print.h"
+#include "netdissect-alloc.h"
+
+#include "pcap-missing.h"
 
 struct printer {
        if_printer f;
@@ -44,71 +48,22 @@ struct printer {
 };
 
 static const struct printer printers[] = {
-       { ether_if_print,       DLT_EN10MB },
-#ifdef DLT_IPNET
-       { ipnet_if_print,       DLT_IPNET },
-#endif
-#ifdef DLT_IEEE802_15_4
-       { ieee802_15_4_if_print, DLT_IEEE802_15_4 },
-#endif
-#ifdef DLT_IEEE802_15_4_NOFCS
-       { ieee802_15_4_if_print, DLT_IEEE802_15_4_NOFCS },
-#endif
-#ifdef DLT_PPI
-       { ppi_if_print,         DLT_PPI },
-#endif
-#ifdef DLT_NETANALYZER
-       { netanalyzer_if_print, DLT_NETANALYZER },
-#endif
-#ifdef DLT_NETANALYZER_TRANSPARENT
-       { netanalyzer_transparent_if_print, DLT_NETANALYZER_TRANSPARENT },
-#endif
-#if defined(DLT_NFLOG) && defined(HAVE_PCAP_NFLOG_H)
-       { nflog_if_print,       DLT_NFLOG},
-#endif
-#ifdef DLT_CIP
-       { cip_if_print,         DLT_CIP },
-#endif
-#ifdef DLT_ATM_CLIP
-       { cip_if_print,         DLT_ATM_CLIP },
-#endif
-#ifdef DLT_IP_OVER_FC
-       { ipfc_if_print,        DLT_IP_OVER_FC },
-#endif
-       { null_if_print,        DLT_NULL },
-#ifdef DLT_LOOP
-       { null_if_print,        DLT_LOOP },
-#endif
 #ifdef DLT_APPLE_IP_OVER_IEEE1394
        { ap1394_if_print,      DLT_APPLE_IP_OVER_IEEE1394 },
-#endif
-#if defined(DLT_BLUETOOTH_HCI_H4_WITH_PHDR) && defined(HAVE_PCAP_BLUETOOTH_H)
-       { bt_if_print,          DLT_BLUETOOTH_HCI_H4_WITH_PHDR},
-#endif
-#ifdef DLT_LANE8023
-       { lane_if_print,        DLT_LANE8023 },
 #endif
        { arcnet_if_print,      DLT_ARCNET },
 #ifdef DLT_ARCNET_LINUX
        { arcnet_linux_if_print, DLT_ARCNET_LINUX },
 #endif
-       { raw_if_print,         DLT_RAW },
-#ifdef DLT_IPV4
-       { raw_if_print,         DLT_IPV4 },
+       { atm_if_print,         DLT_ATM_RFC1483 },
+#ifdef DLT_DSA_TAG_BRCM
+       { brcm_tag_if_print,    DLT_DSA_TAG_BRCM },
 #endif
-#ifdef DLT_IPV6
-       { raw_if_print,         DLT_IPV6 },
+#ifdef DLT_DSA_TAG_BRCM_PREPEND
+       { brcm_tag_prepend_if_print, DLT_DSA_TAG_BRCM_PREPEND },
 #endif
-#ifdef HAVE_PCAP_USB_H
-#ifdef DLT_USB_LINUX
-       { usb_linux_48_byte_print, DLT_USB_LINUX},
-#endif /* DLT_USB_LINUX */
-#ifdef DLT_USB_LINUX_MMAPPED
-       { usb_linux_64_byte_print, DLT_USB_LINUX_MMAPPED},
-#endif /* DLT_USB_LINUX_MMAPPED */
-#endif /* HAVE_PCAP_USB_H */
-#ifdef DLT_SYMANTEC_FIREWALL
-       { symantec_if_print,    DLT_SYMANTEC_FIREWALL },
+#ifdef DLT_BLUETOOTH_HCI_H4_WITH_PHDR
+       { bt_if_print,          DLT_BLUETOOTH_HCI_H4_WITH_PHDR},
 #endif
 #ifdef DLT_C_HDLC
        { chdlc_if_print,       DLT_C_HDLC },
@@ -116,142 +71,185 @@ static const struct printer printers[] = {
 #ifdef DLT_HDLC
        { chdlc_if_print,       DLT_HDLC },
 #endif
-#ifdef DLT_PPP_ETHER
-       { pppoe_if_print,       DLT_PPP_ETHER },
+#ifdef DLT_ATM_CLIP
+       { cip_if_print,         DLT_ATM_CLIP },
 #endif
-#if defined(DLT_PFLOG) && defined(HAVE_NET_IF_PFLOG_H)
-       { pflog_if_print,       DLT_PFLOG },
+#ifdef DLT_CIP
+       { cip_if_print,         DLT_CIP },
 #endif
-       { token_if_print,       DLT_IEEE802 },
-       { fddi_if_print,        DLT_FDDI },
-#ifdef DLT_LINUX_SLL
-       { sll_if_print,         DLT_LINUX_SLL },
+#ifdef DLT_DSA_TAG_DSA
+       { dsa_if_print,         DLT_DSA_TAG_DSA },
+#endif
+#ifdef DLT_DSA_TAG_EDSA
+       { edsa_if_print,        DLT_DSA_TAG_EDSA },
+#endif
+#ifdef DLT_ENC
+       { enc_if_print,         DLT_ENC },
 #endif
+       { ether_if_print,       DLT_EN10MB },
+       { fddi_if_print,        DLT_FDDI },
 #ifdef DLT_FR
        { fr_if_print,          DLT_FR },
 #endif
 #ifdef DLT_FRELAY
        { fr_if_print,          DLT_FRELAY },
 #endif
-#ifdef DLT_MFR
-       { mfr_if_print,         DLT_MFR },
+#ifdef DLT_IEEE802_11
+       { ieee802_11_if_print,  DLT_IEEE802_11},
 #endif
-       { atm_if_print,         DLT_ATM_RFC1483 },
-#ifdef DLT_SUNATM
-       { sunatm_if_print,      DLT_SUNATM },
+#ifdef DLT_IEEE802_11_RADIO_AVS
+       { ieee802_11_radio_avs_if_print, DLT_IEEE802_11_RADIO_AVS },
 #endif
-#ifdef DLT_ENC
-       { enc_if_print,         DLT_ENC },
+#ifdef DLT_IEEE802_11_RADIO
+       { ieee802_11_radio_if_print,    DLT_IEEE802_11_RADIO },
 #endif
-       { sl_if_print,          DLT_SLIP },
-#ifdef DLT_SLIP_BSDOS
-       { sl_bsdos_if_print,    DLT_SLIP_BSDOS },
+#ifdef DLT_IEEE802_15_4
+       { ieee802_15_4_if_print, DLT_IEEE802_15_4 },
 #endif
-#ifdef DLT_LTALK
-       { ltalk_if_print,       DLT_LTALK },
+#ifdef DLT_IEEE802_15_4_NOFCS
+       { ieee802_15_4_if_print, DLT_IEEE802_15_4_NOFCS },
+#endif
+#ifdef DLT_IEEE802_15_4_TAP
+       { ieee802_15_4_tap_if_print, DLT_IEEE802_15_4_TAP },
+#endif
+#ifdef DLT_IP_OVER_FC
+       { ipfc_if_print,        DLT_IP_OVER_FC },
+#endif
+#ifdef DLT_IPNET
+       { ipnet_if_print,       DLT_IPNET },
+#endif
+#ifdef DLT_IPOIB
+       { ipoib_if_print,       DLT_IPOIB },
 #endif
 #ifdef DLT_JUNIPER_ATM1
-       { juniper_atm1_print,   DLT_JUNIPER_ATM1 },
+       { juniper_atm1_if_print, DLT_JUNIPER_ATM1 },
 #endif
 #ifdef DLT_JUNIPER_ATM2
-       { juniper_atm2_print,   DLT_JUNIPER_ATM2 },
+       { juniper_atm2_if_print, DLT_JUNIPER_ATM2 },
+#endif
+#ifdef DLT_JUNIPER_CHDLC
+       { juniper_chdlc_if_print,       DLT_JUNIPER_CHDLC },
+#endif
+#ifdef DLT_JUNIPER_ES
+       { juniper_es_if_print,  DLT_JUNIPER_ES },
+#endif
+#ifdef DLT_JUNIPER_ETHER
+       { juniper_ether_if_print,       DLT_JUNIPER_ETHER },
+#endif
+#ifdef DLT_JUNIPER_FRELAY
+       { juniper_frelay_if_print,      DLT_JUNIPER_FRELAY },
+#endif
+#ifdef DLT_JUNIPER_GGSN
+       { juniper_ggsn_if_print, DLT_JUNIPER_GGSN },
 #endif
 #ifdef DLT_JUNIPER_MFR
-       { juniper_mfr_print,    DLT_JUNIPER_MFR },
+       { juniper_mfr_if_print, DLT_JUNIPER_MFR },
 #endif
 #ifdef DLT_JUNIPER_MLFR
-       { juniper_mlfr_print,   DLT_JUNIPER_MLFR },
+       { juniper_mlfr_if_print, DLT_JUNIPER_MLFR },
 #endif
 #ifdef DLT_JUNIPER_MLPPP
-       { juniper_mlppp_print,  DLT_JUNIPER_MLPPP },
+       { juniper_mlppp_if_print, DLT_JUNIPER_MLPPP },
 #endif
-#ifdef DLT_JUNIPER_PPPOE
-       { juniper_pppoe_print,  DLT_JUNIPER_PPPOE },
+#ifdef DLT_JUNIPER_MONITOR
+       { juniper_monitor_if_print, DLT_JUNIPER_MONITOR },
+#endif
+#ifdef DLT_JUNIPER_PPP
+       { juniper_ppp_if_print, DLT_JUNIPER_PPP },
 #endif
 #ifdef DLT_JUNIPER_PPPOE_ATM
-       { juniper_pppoe_atm_print, DLT_JUNIPER_PPPOE_ATM },
+       { juniper_pppoe_atm_if_print, DLT_JUNIPER_PPPOE_ATM },
 #endif
-#ifdef DLT_JUNIPER_GGSN
-       { juniper_ggsn_print,   DLT_JUNIPER_GGSN },
+#ifdef DLT_JUNIPER_PPPOE
+       { juniper_pppoe_if_print, DLT_JUNIPER_PPPOE },
 #endif
-#ifdef DLT_JUNIPER_ES
-       { juniper_es_print,     DLT_JUNIPER_ES },
+#ifdef DLT_JUNIPER_SERVICES
+       { juniper_services_if_print, DLT_JUNIPER_SERVICES },
 #endif
-#ifdef DLT_JUNIPER_MONITOR
-       { juniper_monitor_print, DLT_JUNIPER_MONITOR },
+#ifdef DLT_LTALK
+       { ltalk_if_print,       DLT_LTALK },
 #endif
-#ifdef DLT_JUNIPER_SERVICES
-       { juniper_services_print, DLT_JUNIPER_SERVICES },
+#ifdef DLT_MFR
+       { mfr_if_print,         DLT_MFR },
 #endif
-#ifdef DLT_JUNIPER_ETHER
-       { juniper_ether_print,  DLT_JUNIPER_ETHER },
+#ifdef DLT_NETANALYZER
+       { netanalyzer_if_print, DLT_NETANALYZER },
 #endif
-#ifdef DLT_JUNIPER_PPP
-       { juniper_ppp_print,    DLT_JUNIPER_PPP },
+#ifdef DLT_NETANALYZER_TRANSPARENT
+       { netanalyzer_transparent_if_print, DLT_NETANALYZER_TRANSPARENT },
 #endif
-#ifdef DLT_JUNIPER_FRELAY
-       { juniper_frelay_print, DLT_JUNIPER_FRELAY },
+#ifdef DLT_NFLOG
+       { nflog_if_print,       DLT_NFLOG},
 #endif
-#ifdef DLT_JUNIPER_CHDLC
-       { juniper_chdlc_print,  DLT_JUNIPER_CHDLC },
+       { null_if_print,        DLT_NULL },
+#ifdef DLT_LOOP
+       { null_if_print,        DLT_LOOP },
+#endif
+#ifdef DLT_PFLOG
+       { pflog_if_print,       DLT_PFLOG },
 #endif
 #ifdef DLT_PKTAP
        { pktap_if_print,       DLT_PKTAP },
 #endif
-#ifdef DLT_IEEE802_11_RADIO
-       { ieee802_11_radio_if_print,    DLT_IEEE802_11_RADIO },
+#ifdef DLT_PPI
+       { ppi_if_print,         DLT_PPI },
 #endif
-#ifdef DLT_IEEE802_11
-       { ieee802_11_if_print,  DLT_IEEE802_11},
+#ifdef DLT_PPP_BSDOS
+       { ppp_bsdos_if_print,   DLT_PPP_BSDOS },
 #endif
-#ifdef DLT_IEEE802_11_RADIO_AVS
-       { ieee802_11_radio_avs_if_print,        DLT_IEEE802_11_RADIO_AVS },
+#ifdef DLT_PPP_SERIAL
+       { ppp_hdlc_if_print,    DLT_PPP_SERIAL },
+#endif
+       { ppp_if_print,         DLT_PPP },
+#ifdef DLT_PPP_PPPD
+       { ppp_if_print,         DLT_PPP_PPPD },
+#endif
+#ifdef DLT_PPP_ETHER
+       { pppoe_if_print,       DLT_PPP_ETHER },
 #endif
 #ifdef DLT_PRISM_HEADER
        { prism_if_print,       DLT_PRISM_HEADER },
 #endif
-       { ppp_if_print,         DLT_PPP },
-#ifdef DLT_PPP_WITHDIRECTION
-       { ppp_if_print,         DLT_PPP_WITHDIRECTION },
+       { raw_if_print,         DLT_RAW },
+#ifdef DLT_IPV4
+       { raw_if_print,         DLT_IPV4 },
 #endif
-#ifdef DLT_PPP_BSDOS
-       { ppp_bsdos_if_print,   DLT_PPP_BSDOS },
+#ifdef DLT_IPV6
+       { raw_if_print,         DLT_IPV6 },
 #endif
-#ifdef DLT_PPP_SERIAL
-       { ppp_hdlc_if_print,    DLT_PPP_SERIAL },
+#ifdef DLT_SLIP_BSDOS
+       { sl_bsdos_if_print,    DLT_SLIP_BSDOS },
+#endif
+       { sl_if_print,          DLT_SLIP },
+#ifdef DLT_LINUX_SLL
+       { sll_if_print,         DLT_LINUX_SLL },
+#endif
+#ifdef DLT_LINUX_SLL2
+       { sll2_if_print,        DLT_LINUX_SLL2 },
+#endif
+#ifdef DLT_SUNATM
+       { sunatm_if_print,      DLT_SUNATM },
+#endif
+#ifdef DLT_SYMANTEC_FIREWALL
+       { symantec_if_print,    DLT_SYMANTEC_FIREWALL },
 #endif
-       { NULL,                 0 },
+       { token_if_print,       DLT_IEEE802 },
+#ifdef DLT_USB_LINUX
+       { usb_linux_48_byte_if_print, DLT_USB_LINUX},
+#endif /* DLT_USB_LINUX */
+#ifdef DLT_USB_LINUX_MMAPPED
+       { usb_linux_64_byte_if_print, DLT_USB_LINUX_MMAPPED},
+#endif /* DLT_USB_LINUX_MMAPPED */
+#ifdef DLT_VSOCK
+       { vsock_if_print,       DLT_VSOCK },
+#endif
+       { NULL,                 0 },
 };
 
-static void    ndo_default_print(netdissect_options *ndo, const u_char *bp,
-                   u_int length);
-
-static void    ndo_error(netdissect_options *ndo, const char *fmt, ...)
-                   __attribute__((noreturn))
-#ifdef __ATTRIBUTE___FORMAT_OK
-                   __attribute__((format (printf, 2, 3)))
-#endif /* __ATTRIBUTE___FORMAT_OK */
-                   ;
-static void    ndo_warning(netdissect_options *ndo, const char *fmt, ...)
-#ifdef __ATTRIBUTE___FORMAT_OK
-                   __attribute__((format (printf, 2, 3)))
-#endif /* __ATTRIBUTE___FORMAT_OK */
-                   ;
-
-static int     ndo_printf(netdissect_options *ndo, const char *fmt, ...)
-#ifdef __ATTRIBUTE___FORMAT_OK
-                    __attribute ((format (printf, 2, 3)))
-#endif /* __ATTRIBUTE___FORMAT_OK */
-                    ;
-
 void
-init_print(netdissect_options *ndo, uint32_t localnet, uint32_t mask,
-    uint32_t timezone_offset)
+init_print(netdissect_options *ndo, uint32_t localnet, uint32_t mask)
 {
-
-       thiszone = timezone_offset;
        init_addrtoname(ndo, localnet, mask);
-       init_checksum();
 }
 
 if_printer
@@ -298,35 +296,102 @@ has_printer(int type)
 }
 
 if_printer
-get_if_printer(netdissect_options *ndo, int type)
+get_if_printer(int type)
 {
-       const char *dltname;
        if_printer printer;
 
        printer = lookup_printer(type);
-       if (printer == NULL) {
-               dltname = pcap_datalink_val_to_name(type);
-               if (dltname != NULL)
-                       (*ndo->ndo_error)(ndo,
-                                         "packet printing is not supported for link type %s: use -w",
-                                         dltname);
-               else
-                       (*ndo->ndo_error)(ndo,
-                                         "packet printing is not supported for link type %d: use -w", type);
-       }
+       if (printer == NULL)
+               printer = unsupported_if_print;
        return printer;
 }
 
+#ifdef ENABLE_INSTRUMENT_FUNCTIONS
+extern int profile_func_level;
+static int pretty_print_packet_level = -1;
+#endif
+
 void
 pretty_print_packet(netdissect_options *ndo, const struct pcap_pkthdr *h,
-    const u_char *sp, u_int packets_captured)
+                   const u_char *sp, u_int packets_captured)
 {
-       u_int hdrlen;
+       u_int hdrlen = 0;
+       int invalid_header = 0;
 
-       if(ndo->ndo_packet_number)
-               ND_PRINT((ndo, "%5u  ", packets_captured));
+       if (ndo->ndo_print_sampling && packets_captured % ndo->ndo_print_sampling != 0)
+               return;
+
+#ifdef ENABLE_INSTRUMENT_FUNCTIONS
+       if (pretty_print_packet_level == -1)
+               pretty_print_packet_level = profile_func_level;
+#endif
 
-       ts_print(ndo, &h->ts);
+       if (ndo->ndo_packet_number)
+               ND_PRINT("%5u  ", packets_captured);
+
+       /* Sanity checks on packet length / capture length */
+       if (h->caplen == 0) {
+               invalid_header = 1;
+               ND_PRINT("[Invalid header: caplen==0");
+       }
+       if (h->len == 0) {
+               if (!invalid_header) {
+                       invalid_header = 1;
+                       ND_PRINT("[Invalid header:");
+               } else
+                       ND_PRINT(",");
+               ND_PRINT(" len==0");
+       } else if (h->len < h->caplen) {
+               if (!invalid_header) {
+                       invalid_header = 1;
+                       ND_PRINT("[Invalid header:");
+               } else
+                       ND_PRINT(",");
+               ND_PRINT(" len(%u) < caplen(%u)", h->len, h->caplen);
+       }
+       if (h->caplen > MAXIMUM_SNAPLEN) {
+               if (!invalid_header) {
+                       invalid_header = 1;
+                       ND_PRINT("[Invalid header:");
+               } else
+                       ND_PRINT(",");
+               ND_PRINT(" caplen(%u) > %u", h->caplen, MAXIMUM_SNAPLEN);
+       }
+       if (h->len > MAXIMUM_SNAPLEN) {
+               if (!invalid_header) {
+                       invalid_header = 1;
+                       ND_PRINT("[Invalid header:");
+               } else
+                       ND_PRINT(",");
+               ND_PRINT(" len(%u) > %u", h->len, MAXIMUM_SNAPLEN);
+       }
+       if (invalid_header) {
+               ND_PRINT("]\n");
+               return;
+       }
+
+       /*
+        * At this point:
+        *   capture length != 0,
+        *   packet length != 0,
+        *   capture length <= MAXIMUM_SNAPLEN,
+        *   packet length <= MAXIMUM_SNAPLEN,
+        *   packet length >= capture length.
+        *
+        * Currently, there is no D-Bus printer, thus no need for
+        * bigger lengths.
+        */
+
+       /*
+        * The header /usr/include/pcap/pcap.h in OpenBSD declares h->ts as
+        * struct bpf_timeval, not struct timeval. The former comes from
+        * /usr/include/net/bpf.h and uses 32-bit unsigned types instead of
+        * the types used in struct timeval.
+        */
+       struct timeval tvbuf;
+       tvbuf.tv_sec = h->ts.tv_sec;
+       tvbuf.tv_usec = h->ts.tv_usec;
+       ts_print(ndo, &tvbuf);
 
        /*
         * Printers must check that they're not walking off the end of
@@ -335,8 +400,35 @@ pretty_print_packet(netdissect_options *ndo, const struct pcap_pkthdr *h,
         * of the netdissect_options structure.
         */
        ndo->ndo_snapend = sp + h->caplen;
+       ndo->ndo_packetp = sp;
+
+       ndo->ndo_protocol = "";
+       ndo->ndo_ll_hdr_len = 0;
+       switch (setjmp(ndo->ndo_early_end)) {
+       case 0:
+               /* Print the packet. */
+               (ndo->ndo_if_printer)(ndo, h, sp);
+               break;
+       case ND_TRUNCATED:
+               /* A printer quit because the packet was truncated; report it */
+               nd_print_trunc(ndo);
+               /* Print the full packet */
+               ndo->ndo_ll_hdr_len = 0;
+#ifdef ENABLE_INSTRUMENT_FUNCTIONS
+               /* truncation => reassignment */
+               profile_func_level = pretty_print_packet_level;
+#endif
+               break;
+       }
+       hdrlen = ndo->ndo_ll_hdr_len;
 
-        hdrlen = (ndo->ndo_if_printer)(ndo, h, sp);
+       /*
+        * Empty the stack of packet information, freeing all pushed buffers;
+        * if we got here by a printer quitting, we need to release anything
+        * that didn't get released because we longjmped out of the code
+        * before it popped the packet information.
+        */
+       nd_pop_all_packet_info(ndo);
 
        /*
         * Restore the original snapend, as a printer might have
@@ -360,7 +452,7 @@ pretty_print_packet(netdissect_options *ndo, const struct pcap_pkthdr *h,
                         */
                        if (h->caplen > hdrlen)
                                hex_and_ascii_print(ndo, "\n\t", sp + hdrlen,
-                                   h->caplen - hdrlen);
+                                                   h->caplen - hdrlen);
                }
        } else if (ndo->ndo_xflag) {
                /*
@@ -370,7 +462,7 @@ pretty_print_packet(netdissect_options *ndo, const struct pcap_pkthdr *h,
                        /*
                         * Include the link-layer header.
                         */
-                        hex_print(ndo, "\n\t", sp, h->caplen);
+                       hex_print(ndo, "\n\t", sp, h->caplen);
                } else {
                        /*
                         * Don't include the link-layer header - and if
@@ -379,7 +471,7 @@ pretty_print_packet(netdissect_options *ndo, const struct pcap_pkthdr *h,
                         */
                        if (h->caplen > hdrlen)
                                hex_print(ndo, "\n\t", sp + hdrlen,
-                                          h->caplen - hdrlen);
+                                         h->caplen - hdrlen);
                }
        } else if (ndo->ndo_Aflag) {
                /*
@@ -401,7 +493,8 @@ pretty_print_packet(netdissect_options *ndo, const struct pcap_pkthdr *h,
                }
        }
 
-       ND_PRINT((ndo, "\n"));
+       ND_PRINT("\n");
+       nd_free_all(ndo);
 }
 
 /*
@@ -414,12 +507,13 @@ ndo_default_print(netdissect_options *ndo, const u_char *bp, u_int length)
 }
 
 /* VARARGS */
-static void
-ndo_error(netdissect_options *ndo, const char *fmt, ...)
+static void NORETURN PRINTFLIKE(3, 4)
+ndo_error(netdissect_options *ndo, status_exit_codes_t status,
+          FORMAT_STRING(const char *fmt), ...)
 {
        va_list ap;
 
-       if(ndo->program_name)
+       if (ndo->program_name)
                (void)fprintf(stderr, "%s: ", ndo->program_name);
        va_start(ap, fmt);
        (void)vfprintf(stderr, fmt, ap);
@@ -430,17 +524,17 @@ ndo_error(netdissect_options *ndo, const char *fmt, ...)
                        (void)fputc('\n', stderr);
        }
        nd_cleanup();
-       exit(1);
+       exit(status);
        /* NOTREACHED */
 }
 
 /* VARARGS */
-static void
-ndo_warning(netdissect_options *ndo, const char *fmt, ...)
+static void PRINTFLIKE(2, 3)
+ndo_warning(netdissect_options *ndo, FORMAT_STRING(const char *fmt), ...)
 {
        va_list ap;
 
-       if(ndo->program_name)
+       if (ndo->program_name)
                (void)fprintf(stderr, "%s: ", ndo->program_name);
        (void)fprintf(stderr, "WARNING: ");
        va_start(ap, fmt);
@@ -453,8 +547,9 @@ ndo_warning(netdissect_options *ndo, const char *fmt, ...)
        }
 }
 
-static int
-ndo_printf(netdissect_options *ndo, const char *fmt, ...)
+/* VARARGS */
+static int PRINTFLIKE(2, 3)
+ndo_printf(netdissect_options *ndo, FORMAT_STRING(const char *fmt), ...)
 {
        va_list args;
        int ret;
@@ -464,7 +559,8 @@ ndo_printf(netdissect_options *ndo, const char *fmt, ...)
        va_end(args);
 
        if (ret < 0)
-               ndo_error(ndo, "Unable to write output: %s", pcap_strerror(errno));
+               ndo_error(ndo, S_ERR_ND_WRITE_FILE,
+                         "Unable to write output: %s", pcap_strerror(errno));
        return (ret);
 }
 
@@ -476,9 +572,3 @@ ndo_set_function_pointers(netdissect_options *ndo)
        ndo->ndo_error=ndo_error;
        ndo->ndo_warning=ndo_warning;
 }
-/*
- * Local Variables:
- * c-style: whitesmith
- * c-basic-offset: 8
- * End:
- */