From: Stuart Henderson Subject: Re: MAINTAINER: net/kismet link against net/pcap and some fixes To: Sebastian Reitenbach Cc: ports Date: Thu, 14 May 2026 15:33:41 +0100 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.