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
kismet.diff
Description: Binary data
