Hi Stuart,

On Thu, May 14, 2026 at 4:33 PM Stuart Henderson <[email protected]>
wrote:

> 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.
>


I tried multiple ways to get it as above working, but failed, I'll give it
another try again.



>
> : --- 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...)
>
>
I'll look into that as well.


>
> : 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?
>

this was initially to make it work with our base libpcap. I assume it's 99%
used on Linux,
and they use the libpcap we have in ports now, they don't run into the
issue, as these DLTs
 are all there. This only happens on OS that link against older libpcaps,
and only when you
sniffed i.e. BTLE or NRF with kismet, so probably very rare.

Since linking against libpcap from ports now, I'' just drop this whole
patch, as we won't run
into the issue anymore.


> : +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?
>

a bit later, errno is used



>
> : ++        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 ?
>

yeah, I'll leave that complete file out, because since linking to the other
libpcap,
we can't run into the trouble of the unknown DLT.


>
> : +
> : +@@ -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.
>


-- 
https://buzzdeee.reitenba.ch

Reply via email to