Hi,

indeed all my testing with configure to get it right to pass in cflags and
ldflags to find and link against
libpcap from ports, I missed to realize, that the only thing is the patch I
have to configure.ac.

Therefore Makefile is now much cleaner, as well as I figured out, how to
deal with the configure check
to "just work".

I dropped the patch for the kismetdb_to_pcap, as the issue won't show up
with kismet linked against
ports libpcap.

hope that's fine now?


cheers,
Sebastian

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


-- 
https://buzzdeee.reitenba.ch

Attachment: kismet.diff
Description: Binary data

Reply via email to