On 2026/05/08 19:58, Sebastian Reitenbach wrote:
> Hi,
> 
> this links kismet against net/pcap, which eventually allows the 
> kismetdb_to_pcap to succeed
> without a crasher because our pcap doesn't know all DLTs kismet expects it to 
> know, ie. BTLE or
> Zigbee captured traffic. Pcap can then be read in in Wireshark for example.
> 
> Other than that: 
> * capture_nrf_52840_capture_nrf_52840_c similar patches
> * as capture_nrf_51822_capture_nrf_51822_c has, but I haven't yet got the 
> nice!Nano I have to
> detect any Zigbee packages. Maybe antenna is just too bad, and neighbours 
> devices too far away
> ;)
> * capture_ti_cc_2531_capture_ti_cc_2531_c makes my TI CC2531 with sniffer 
> firmware work!
> already upstreamed.
> * log_tools_kismetdb_to_pcap_cc some additional debugging aid, already 
> upstreamed
> * updated README, besides smaller additions, esp. mention nrf_52840 and 
> ti_cc_2531
> 
> patch attached, I'm especially looking for feedback on the linking against 
> net/pcap.
> 
> 
> 
> cheers,
> Sebastian
> 
> 
> --
> https://buzzdeee.reitenba.ch

: -WANTLIB += ${COMPILER_LIBCXX} c crypto m mosquitto pcap pcre2-8
: +WANTLIB += ${COMPILER_LIBCXX} c crypto m mosquitto pcre2-8
:  WANTLIB += rtlsdr sqlite3 ssl usb-1.0 util websockets z
: +WANTLIB += lib/libpcap/pcap
:  
:  # C++20
:  COMPILER=    base-clang ports-gcc
: @@ -36,7 +37,12 @@
:  LDFLAGS_ports-gcc= -latomic
:  LDFLAGS=     -L${X11BASE}/lib -L${LOCALBASE}/lib 
${LDFLAGS_${CHOSEN_COMPILER}}
:  
: +PCAP_CFLAGS !=    pkg-config --cflags libepcap
: +PCAP_LIBS !=      pkg-config --libs libepcap

don't use != unless *absolutely* unavoidable, every time the makefile
is parsed for whatever reason (even if it's just "make show=PKGNAMES" or
something) the command is run (and while pkgconf is much better than
old pkg-config, it's still not really cheap)...

:  CONFIGURE_ENV=       CPPFLAGS="-I${X11BASE}/include -I${LOCALBASE}/include" \
: +             libepcap_CFLAGS="${PCAP_CFLAGS}" \
: +             libepcap_LIBS="${PCAP_LIBS}" \

passing in from the makefile shouldn't be needed at all anyway as you
have already patched the autoconf file to do this.

if you _did_ need to pass in from the makefile, it would usually be
better to use e.g. libepcap_CFLAGS="`pkg-config --cflags libepcap`" etc,
so that the command is only run when shelling out to run configure
anyway.

: --- patches/patch-configure_ac        19 Jan 2026 13:00:38 -0000      1.1
: +++ patches/patch-configure_ac        8 May 2026 17:49:35 -0000
: @@ -1,6 +1,6 @@
:  - don't force -O3
:  - GCC's libatomic should not be pulled in just because it exists
: -- libstdc++ should n9t be explicitly linked (use "c++" as a linker instead)
: +- libstdc++ should not be explicitly linked (use "c++" as a linker instead)
:  
:  Index: configure.ac
:  --- configure.ac.orig
: @@ -59,3 +59,32 @@
:   AC_SUBST(CXXLIBS)
:   
:   # Does the compiler handle various std::foo namespaces properly?
: +@@ -1187,20 +1156,20 @@ AC_SUBST(LIBWSLIBS)
: + AC_SUBST(LIBWSCFLAGS)
: + 
: + # Look for libpcap via pkg-config
: +-have_libpcap=no
: +-PKG_CHECK_MODULES([libpcap], [libpcap], [
: +-    have_libpcap=yes
: +-    AC_DEFINE(HAVE_LIBPCAP, 1, libpcap packet capture lib)
: ++have_libepcap=no
: ++PKG_CHECK_MODULES([libepcap], [libepcap], [
: ++    have_libepcap=yes
: ++    AC_DEFINE(HAVE_LIBPCAP, 1, libepcap packet capture lib)
: + 
: +-    PCAPLIBS=`pkg-config --libs libpcap`
: +-    PCAPCFLAGS=`pkg-config --cflags libpcap`
: ++    PCAPLIBS=`pkg-config --libs libepcap`
: ++    PCAPCFLAGS=`pkg-config --cflags libepcap`
: +     pcap=yes
: +     ], [
: +-    AC_MSG_WARN(No libpcap found in pkg-config, will check system paths.)
: ++    AC_MSG_WARN(No libepcap found in pkg-config, will check system paths.)
: +     ])
: + 
: + # Look for pcap using our legacy mode
: +-if test "$have_libpcap"x != "yesx"; then
: ++if test "$have_libepcap"x != "yesx"; then
: +     AC_CHECK_LIB([pcap], [pcap_open_live],
: +         AC_DEFINE(HAVE_LIBPCAP, 1, libpcap packet capture lib) 
foundsyspcap=yes,
: +         AC_MSG_ERROR(Libpcap required for proper operation))

I think you should *only* change the name of the pkg-config file being
checked for. Don't rename their "have_libpcap" variable or the prefix
used for other variables, that is:


| have_libpcap=no
| PKG_CHECK_MODULES([libpcap], [libpcap], [
                                ^^^^^^^ here
                     ^ not here, this is the prefix for autoconf variables
|     have_libpcap=yes
|     AC_DEFINE(HAVE_LIBPCAP, 1, libpcap packet capture lib)
|     PCAPLIBS=`pkg-config --libs libpcap`
                                  ^^^^^^^ here
|     PCAPCFLAGS=`pkg-config --cflags libpcap`
                                      ^^^^^^^ here
|     pcap=yes
|     ], [
|     AC_MSG_WARN(No libpcap found in pkg-config, will check system paths.)
|     ])
| 
| # Look for pcap using our legacy mode
| if test "$have_libpcap"x != "yesx"; then
|     AC_CHECK_LIB([pcap], [pcap_open_live],
|         AC_DEFINE(HAVE_LIBPCAP, 1, libpcap packet capture lib) 
foundsyspcap=yes,
|         AC_MSG_ERROR(Libpcap required for proper operation))

(their autoconf checks are a bit strange, because they're asking
PKG_CHECK_MODULES to determine libs/cflags, then ignoring them and
asking pkg-config directly, but whatever...)


: Index: patches/patch-log_tools_kismetdb_to_pcap_cc
: ===================================================================
: RCS file: patches/patch-log_tools_kismetdb_to_pcap_cc
: diff -N patches/patch-log_tools_kismetdb_to_pcap_cc
: --- /dev/null 1 Jan 1970 00:00:00 -0000
: +++ patches/patch-log_tools_kismetdb_to_pcap_cc       8 May 2026 17:49:35 
-0000
: @@ -0,0 +1,226 @@
: +Prevent crasher when hitting unknown DLT

any idea what's different compared to other OS? surely if there's a
problem it will affect them too?

: +Index: log_tools/kismetdb_to_pcap.cc
: +--- log_tools/kismetdb_to_pcap.cc.orig
: ++++ log_tools/kismetdb_to_pcap.cc
: +@@ -222,16 +222,31 @@ void write_pcap_packet(FILE *pcap_file, const std::str
: +     hdr.incl_len = packet.size();
: +     hdr.orig_len = packet.size();
: + 
: +-    if (fwrite(&hdr, sizeof(pcap_packet_hdr_t), 1, pcap_file) != 1)
: +-        throw std::runtime_error(fmt::format("error writing pcap packet: {} 
(errno {})",
: +-                    strerror(errno), errno));
: ++    // Skip empty packets to avoid write errors and malformed pcap blocks
: ++    if (packet.empty()) {
: ++        fmt::print(stderr, "DEBUG: Skipping empty pcap packet for TS 
{}.{}\n",
: ++                   ts_sec, ts_usec);
: ++        return;
: ++    }
: + 
: +-    if (fwrite(packet.data(), packet.size(), 1, pcap_file) != 1)
: +-        throw std::runtime_error(fmt::format("error writing pcap packet: {} 
(errno {})",
: +-                    strerror(errno), errno));

: ++    // Clear errno to avoid reporting stale "No such file" errors
: ++    errno = 0;

not sure that makes sense? -

: ++    if (fwrite(&hdr, sizeof(pcap_packet_hdr_t), 1, pcap_file) != 1) {

"fwrite() returns a value less than nmemb only if a write error has occurred"
so why is the errno zeroing needed?

: ++        int errsv = errno;
: ++        throw std::runtime_error(fmt::format("failed writing pcap HEADER: 
{} (errno {})",
: ++                    errsv ? strerror(errsv) : "Unknown/Buffered Error", 
errsv));
: ++    }

or, if it is needed, why is it not done here?

: ++    if (fwrite(packet.data(), packet.size(), 1, pcap_file) != 1) {
: ++        int errsv = errno;
: ++        throw std::runtime_error(fmt::format("failed writing pcap DATA 
(size {}): {} (errno {})",
: ++                    packet.size(), errsv ? strerror(errsv) : 
"Unknown/Buffered Error", errsv));
: ++    }
: + }
: + 
: + 
: ++
: + FILE *open_pcapng_file(const std::string& path, bool force) {
: +     struct stat statbuf;
: +     FILE *pcapng_file;
: +@@ -465,6 +480,13 @@ void write_pcapng_packet(FILE *pcapng_file, const std:
: +         unsigned long ts_sec, unsigned long ts_usec, const std::string& tag,
: +         unsigned int ngindex, double lat, double lon, double alt) {
: + 
: ++    // Skip empty packets to avoid write errors and malformed pcapng blocks
: ++    if (packet.empty()) {
: ++        fmt::print(stderr, "DEBUG: Skipping empty pcapng packet at TS 
{}.{}\n",
: ++                   ts_sec, ts_usec);
: ++        return;
: ++    }
: ++
: +     // Assemble the packet in the file in steps to avoid another memcpy
: +     pcapng_epb_t epb;
: + 
: +@@ -501,24 +523,34 @@ void write_pcapng_packet(FILE *pcapng_file, const std:
: +     epb.captured_length = packet.size();
: +     epb.original_length = packet.size();
: + 
: +-    if (fwrite(&epb, sizeof(pcapng_epb_t), 1, pcapng_file) != 1)
: +-        throw std::runtime_error(fmt::format("error writing pcapng packet 
header: {} (errno {})",
: +-                strerror(errno), errno));
: ++    // Clear errno for clean reporting
: ++    errno = 0;
: + 
: +-    if (fwrite(packet.data(), packet.size(), 1, pcapng_file) != 1)
: +-        throw std::runtime_error(fmt::format("error writing pcapng packet 
content: {} (errno {})",
: +-                    strerror(errno), errno));
: ++    if (fwrite(&epb, sizeof(pcapng_epb_t), 1, pcapng_file) != 1) {
: ++        int errsv = errno;
: ++        throw std::runtime_error(fmt::format("failed writing pcapng EPB 
HEADER: {} (errno {})",
: ++                    errsv ? strerror(errsv) : "Unknown/Buffered Error", 
errsv));
: ++    }
: + 
: ++    if (fwrite(packet.data(), packet.size(), 1, pcapng_file) != 1) {
: ++        int errsv = errno;
: ++        throw std::runtime_error(fmt::format("failed writing pcapng DATA 
(size {}): {} (errno {})",
: ++                    packet.size(), errsv ? strerror(errsv) : 
"Unknown/Buffered Error", errsv));
: ++    }
: ++
: +     // Data has to be 32bit padded
: +     uint32_t pad = 0;
: +     size_t pad_sz = 0;
: + 
: +     pad_sz = PAD_TO_32BIT(packet.size()) - packet.size();
: + 
: +-    if (pad_sz > 0)
: +-        if (fwrite(&pad, pad_sz, 1, pcapng_file) != 1)
: +-            throw std::runtime_error(fmt::format("error writing pcapng 
packet padding: {} (errno {})",
: +-                        strerror(errno), errno));
: ++    if (pad_sz > 0) {
: ++        if (fwrite(&pad, pad_sz, 1, pcapng_file) != 1)  {
: ++            int errsv = errno;
: ++            throw std::runtime_error(fmt::format("failed writing pcapng 
PADDING: {} (errno {})",
: ++                        errsv ? strerror(errsv) : "Unknown/Buffered Error", 
errsv));
: ++        }
: ++    }
: + 
: +     pcapng_option_t opt;
: + 
: +@@ -526,20 +558,27 @@ void write_pcapng_packet(FILE *pcapng_file, const std:
: +         opt.option_code = PCAPNG_OPT_COMMENT;
: +         opt.option_length = tag.length();
: + 
: +-        if (fwrite(&opt, sizeof(pcapng_option_t), 1, pcapng_file) != 1) 
: +-            throw std::runtime_error(fmt::format("error writing pcapng 
packet option: {} (errno {})",
: +-                        strerror(errno), errno));
: ++        if (fwrite(&opt, sizeof(pcapng_option_t), 1, pcapng_file) != 1){
: ++            int errsv = errno;
: ++            throw std::runtime_error(fmt::format("failed writing pcapng 
OPTION HEADER: {} (errno {})",
: ++                errsv ? strerror(errsv) : "Unknown error", errsv));
: ++        }
: + 
: +-        if (fwrite(tag.c_str(), tag.length(), 1, pcapng_file) != 1)
: +-            throw std::runtime_error(fmt::format("error writing pcapng 
packet option: {} (errno {})",
: +-                        strerror(errno), errno));
: ++        if (fwrite(tag.c_str(), tag.length(), 1, pcapng_file) != 1) {
: ++            int errsv = errno;
: ++            throw std::runtime_error(fmt::format("failed writing pcapng 
OPTION DATA (tag): {} (errno {})",
: ++                errsv ? strerror(errsv) : "Unknown error", errsv));
: ++        }
: + 
: +         pad_sz = PAD_TO_32BIT(tag.length()) - tag.length();
: + 
: +-        if (pad_sz > 0)
: +-            if (fwrite(&pad, pad_sz, 1, pcapng_file) != 1)
: +-                throw std::runtime_error(fmt::format("error writing pcapng 
packet option: {} (errno {})",
: +-                            strerror(errno), errno));
: ++        if (pad_sz > 0) {
: ++            if (fwrite(&pad, pad_sz, 1, pcapng_file) != 1) {
: ++                int errsv = errno;
: ++                throw std::runtime_error(fmt::format("failed writing pcapng 
OPTION PADDING: {} (errno {})",
: ++                    errsv ? strerror(errsv) : "Unknown error", errsv));
: ++            }
: ++        }
: +     }
: + 
: +     // If we have gps data, tag the packet with a kismet custom GPS entry 
under the kismet PEN
: +@@ -590,42 +629,55 @@ void write_pcapng_packet(FILE *pcapng_file, const std:
: + 
: +         // Lon, lat, [alt]
: +         u.u32 = double_to_fixed3_7(lon);
: +-        if (fwrite(&u, sizeof(uint32_t), 1, pcapng_file) != 1) 
: +-            throw std::runtime_error(fmt::format("error writing packet gps: 
{} (errno {})",
: +-                        strerror(errno), errno));
: ++        if (fwrite(&u, sizeof(uint32_t), 1, pcapng_file) != 1){
: ++            int errsv = errno;
: ++            throw std::runtime_error(fmt::format("failed writing pcapng GPS 
LONGITUDE: {} (errno {})",
: ++                errsv ? strerror(errsv) : "Unknown/Buffered Error", errsv));
: ++        }
: + 
: +         u.u32 = double_to_fixed3_7(lat);
: +-        if (fwrite(&u, sizeof(uint32_t), 1, pcapng_file) != 1) 
: +-            throw std::runtime_error(fmt::format("error writing packet gps: 
{} (errno {})",
: +-                        strerror(errno), errno));
: ++        if (fwrite(&u, sizeof(uint32_t), 1, pcapng_file) != 1){
: ++            int errsv = errno;
: ++            throw std::runtime_error(fmt::format("failed writing pcapng GPS 
LATITUDE: {} (errno {})",
: ++                errsv ? strerror(errsv) : "Unknown/Buffered Error", errsv));
: ++        }
: + 
: +         if (alt != 0) {
: +             u.u32 = double_to_fixed6_4(alt);
: +-            if (fwrite(&u, sizeof(uint32_t), 1, pcapng_file) != 1) 
: +-                throw std::runtime_error(fmt::format("error writing packet 
gps: {} (errno {})",
: +-                            strerror(errno), errno));
: ++            if (fwrite(&u, sizeof(uint32_t), 1, pcapng_file) != 1) {
: ++                int errsv = errno;
: ++                throw std::runtime_error(fmt::format("failed writing pcapng 
GPS ALTITUDE: {} (errno {})",
: ++                    errsv ? strerror(errsv) : "Unknown/Buffered Error", 
errsv));
: ++            }
: +         }
: + 
: +         pad_sz = PAD_TO_32BIT(copt.option_length) - copt.option_length;
: + 
: +-        if (pad_sz > 0)
: +-            if (fwrite(&pad, pad_sz, 1, pcapng_file) != 1)
: +-                throw std::runtime_error(fmt::format("error writing pcapng 
packet option: {} (errno {})",
: +-                            strerror(errno), errno));
: ++        if (pad_sz > 0) {
: ++            if (fwrite(&pad, pad_sz, 1, pcapng_file) != 1) {
: ++                int errsv = errno;
: ++                throw std::runtime_error(fmt::format("failed writing pcapng 
GPS OPTION PADDING: {} (errno {})",
: ++                    errsv ? strerror(errsv) : "Unknown/Buffered Error", 
errsv));
: ++            }
: ++        }
: +     }
: + 
: +     opt.option_code = PCAPNG_OPT_ENDOFOPT;
: +     opt.option_length = 0;
: + 
: +-    if (fwrite(&opt, sizeof(pcapng_option_t), 1, pcapng_file) != 1) 
: +-        throw std::runtime_error(fmt::format("error writing packet 
end-of-options: {} (errno {})",
: +-                    strerror(errno), errno));
: ++    if (fwrite(&opt, sizeof(pcapng_option_t), 1, pcapng_file) != 1) {
: ++        int errsv = errno;
: ++        throw std::runtime_error(fmt::format("failed writing pcapng 
END-OF-OPTIONS: {} (errno {})",
: ++            errsv ? strerror(errsv) : "Unknown/Buffered Error", errsv));
: ++    }
: + 
: +     data_sz += 4;
: + 
: +-    if (fwrite(&data_sz, 4, 1, pcapng_file) != 1)
: +-        throw std::runtime_error(fmt::format("error writing packet 
end-of-packet: {} (errno {})",
: +-                    strerror(errno), errno));
: ++    if (fwrite(&data_sz, 4, 1, pcapng_file) != 1) {
: ++        int errsv = errno;
: ++        throw std::runtime_error(fmt::format("failed writing pcapng BLOCK 
TRAILER (total length): {} (errno {})",
: ++            errsv ? strerror(errsv) : "Unknown/Buffered Error", errsv));
: ++    }
: + }

a lot of this just seems to be rewriting the checks to do pretty
much exactly the same thing ?

: + 
: +@@ -975,8 +1027,10 @@ int main(int argc, char *argv[]) {
: +             fmt::print("Datasource #{} ({} {} {}) {} packets\n", 
: +                     ifnum++, i->uuid, i->name, i->interface, 
i->num_packets);
: +             for (auto d : i->dlts) {
: ++                const char* n = pcap_datalink_val_to_name(d);
: ++                const char* v = pcap_datalink_val_to_description(d);
: +                 fmt::print("   DLT {}: {} {}\n",
: +-                        d, pcap_datalink_val_to_name(d), 
pcap_datalink_val_to_description(d));
: ++                        d, n ? n : "unknown", v ? v : "unknown");
: +             }
: + 
: +             if (i->dlts.size() == 0) 
: Index: pkg/README
: ===================================================================
: RCS file: /cvs/ports/net/kismet/pkg/README,v
: diff -u -r1.1 README
: --- pkg/README        19 Jan 2026 13:00:38 -0000      1.1
: +++ pkg/README        8 May 2026 17:49:35 -0000
: @@ -8,11 +8,22 @@
:  The following capture drivers are known to work:
:    * openbsd_wifi (autodetected)
:    * sdr_rtladsb (autodetected)
: +    * planes
:    * sdr_rtl433 (autodetected)
: +    * meters
:    * nrf_51822 (not autodetected)
: +    * Bluetooth LE
:      * use with:
:         * -c nrf51822:type=nrf51822,device=/dev/cuaU0,name=adafruit
: -
: +       * tested with Adafruit Bluefruit sniffer as well as nrf52840 
: +         nice!Nano with Bluetooth sniffer firmware
: +  * nrf_52840 (not autodetected)
: +    * Zigbee
: +    * use with:
: +       * -c nrf52840:type=nrf52840,device=/dev/cuaU0,name=niceNano
: +       * note: haven't seen it reporting any packets yet using a nice!Nano
: +  * ti_cc_2531 (autodetected)
: +    * Zigbee
:  
:  Many other capture drivers are enabled. They are untested,
:  but may work as well.

Reply via email to