Download raw body.
MAINTAINER: net/kismet link against net/pcap and some fixes
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 <stu@spacehopper.org>
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
MAINTAINER: net/kismet link against net/pcap and some fixes