Kismet: Updates
parent
bc96b93fdd
commit
8ee88c128c
|
@ -1,14 +1,15 @@
|
|||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=kismet-hak5
|
||||
PKG_VERSION:=master
|
||||
PKG_VERSION:=kismet-2019-07-R1
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://www.kismetwireless.net/git/kismet.git
|
||||
PKG_SOURCE_VERSION:=HEAD
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_SOURCE_URL:=https://github.com/kismetwireless/kismet.git
|
||||
PKG_SOURCE_VERSION:=d3fc27147bb6f4cdca6c3d0bd78866e74bb6e293
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
|
@ -19,15 +20,16 @@ HOST_BUILD_DEPENDS:=protobuf/host
|
|||
define Package/kismet-hak5
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
TITLE:=Kismet
|
||||
TITLE:=Kismet (Hak5)
|
||||
URL:=https://www.kismetwireless.net/
|
||||
DEPENDS:=+libpthread +libpcap +libpcre +libmicrohttpd +libnl +libcap +libstdcpp +libncurses +libsqlite3 +zlib +protobuf +libprotobuf-c +libdw
|
||||
SUBMENU:=wireless
|
||||
endef
|
||||
|
||||
define Package/kismet-hak5/description
|
||||
Kismet wireless capture and IDS
|
||||
Latest web-ui based Kismet
|
||||
Linux Wi-Fi and Bluetooth capture tools
|
||||
Kismet wireless capture and IDS
|
||||
Latest web UI based Kismet
|
||||
Linux Wi-Fi and Bluetooth capture tools
|
||||
endef
|
||||
|
||||
define Build/Configure
|
||||
|
@ -61,7 +63,9 @@ define Package/kismet-hak5/install
|
|||
$(INSTALL_DIR) $(1)/etc/kismet/
|
||||
$(INSTALL_CONF) ./files/kismet_site.conf $(1)/etc/kismet/
|
||||
$(INSTALL_CONF) $(PKG_BUILD_DIR)/conf/kismet.conf $(1)/etc/kismet
|
||||
$(INSTALL_CONF) $(PKG_BUILD_DIR)/conf/kismet_80211.conf $(1)/etc/kismet
|
||||
$(INSTALL_CONF) $(PKG_BUILD_DIR)/conf/kismet_alerts.conf $(1)/etc/kismet
|
||||
$(INSTALL_CONF) $(PKG_BUILD_DIR)/conf/kismet_filter.conf $(1)/etc/kismet
|
||||
$(INSTALL_CONF) $(PKG_BUILD_DIR)/conf/kismet_httpd.conf $(1)/etc/kismet
|
||||
$(INSTALL_CONF) $(PKG_BUILD_DIR)/conf/kismet_logging.conf $(1)/etc/kismet
|
||||
$(INSTALL_CONF) $(PKG_BUILD_DIR)/conf/kismet_memory.conf $(1)/etc/kismet
|
||||
|
|
|
@ -1,401 +0,0 @@
|
|||
REMEMBER: I don't always update the changelog for newcore, check the SVN
|
||||
log for current progress
|
||||
|
||||
Apr 20 2006 devel Fixed BSSID protocol in kismet_server
|
||||
Added various sources
|
||||
Added BSSID protocol decoder to client
|
||||
Apr 07 2006 devel Added server picker window
|
||||
Added "add source" window
|
||||
Mar 20 2006 devel Added keepalive to drone protocol
|
||||
Mar 12 2006 devel I know it's been a while, stuff going on in life, sorry.
|
||||
Added CARD protocol support to kp_frontend
|
||||
Changed behavior of kp_Scrollable_Table to add a row
|
||||
during a replace of a nonexistent row
|
||||
Feb 22 2006 devel Lots of un-changelog'd work in svn
|
||||
Increased max iwpriv ioctls per interface, will produce
|
||||
a different error on madwifi-ng using madwifi-old sources
|
||||
Finished cli matrix widget
|
||||
Added ModalAlert panel
|
||||
"File->Connect" actually connects to the Kismet server
|
||||
Feb 02 2006 devel More work on panels client
|
||||
Work on new tcp client code
|
||||
Fixed stupid error in server that didn't send capabilities
|
||||
Jan 16 2006 devel Finished client panel single input line widget
|
||||
Fixed menu not eating input when selecting nonexistent
|
||||
menus or items via keyboard
|
||||
Fixed consecutive disabled items in menus
|
||||
Fixed stupid error in window positioning
|
||||
Added button widget
|
||||
Added "Connect" demo window
|
||||
Jan 12 2006 devel Finished client panel menu widget code
|
||||
Finished client panel arbitrary text scroller widget code
|
||||
Added Madwifi-NG support (with dyanamic interface
|
||||
creation and destruction support)
|
||||
Removed prism2 header length validation, not needed and
|
||||
some drivers are broken
|
||||
Split widgets and windows into their own files
|
||||
Added client panel 2-field widget
|
||||
Added picking list type demo
|
||||
Added inline text style formatting class, added to
|
||||
freetext widget
|
||||
Jan 08 2006 devel Started newcore client development (Current client code
|
||||
is demo only and will not do anything useful)
|
||||
Changed menu drivers to go to menubar mode and allow
|
||||
picking the menu by underlined key
|
||||
Dec 29 2005 devel Added runstate loaders to kismet_server (do not use yet)
|
||||
Added runstate support to gpsxml
|
||||
Added runstate logging to netracker
|
||||
Added runstate loading to netracker
|
||||
Added runstate net totals logging/loading
|
||||
Runstate loading should be usable
|
||||
Dec 28 2005 devel Added runstate dumpfile framework for freezing the Kismet
|
||||
running state
|
||||
Tweaked runstate dumpfile parsing
|
||||
Added bcm43xx source
|
||||
Started adding dumpfile resume code
|
||||
Dec 21 2005 devel Fixed error in netframe caching
|
||||
Dec 19 2005 devel Added dynamic source creation/removal via ADDSOURCE and
|
||||
DELSOURCE commands
|
||||
Dec 18 2005 devel Fixed drone starting if drone server doesn't start
|
||||
Added --source-options command line switch
|
||||
Dec 16 2005 devel Fixed vector resize with uclibc++
|
||||
Added uclibc++ autodetect in autoconf
|
||||
Added libm autodetect in autoconf
|
||||
Removed const qualifier in macaddr.h to allow compiling on
|
||||
uclibc c++
|
||||
Dec 15 2005 devel Added remote drone name to messages passed from it
|
||||
Fixed drone stream syncing problem which caused sentinel
|
||||
errors
|
||||
Fixed compilation error when libpcap disabled
|
||||
Dec 14 2005 devel Fixed queuing of dumpfiles when dumping is disabled
|
||||
Dec 13 2005 devel Fixed loading of servername in server/drone
|
||||
Restored wrt54prism capture source for OpenWRT
|
||||
Fixed packet processing loop in packetsource_drone
|
||||
Dec 12 2005 devel Revamped AddSource callback API into a generic SourceAction
|
||||
API
|
||||
Wrote drone interface channel push code
|
||||
Added SourceAction hooks for setting hop, vectors
|
||||
Added drone server-side handling of channelset for hopping
|
||||
and vector
|
||||
Changed internal channel representation to unsigned int
|
||||
Added packet sending to drone client
|
||||
Added channelset packet generation to drone client
|
||||
Added proper bitmap handling of channelset frames in
|
||||
drone server
|
||||
Added channel sequence command (CHANSEQ)
|
||||
Fixed card commands (hop, etc) from segfaulting
|
||||
Fixed dumpfiles unregistering callbacks during destruction
|
||||
Fixed more blatant errors in uuid
|
||||
Fixed stupid errors in drone server handling
|
||||
Dec 11 2005 devel Added fix to ringbuf from Shane Schisler
|
||||
Added drone_source_packet generators to drone protocol to
|
||||
push a capture source upstream
|
||||
Added endian-flipping to bitmap fields in drone protocol
|
||||
Completed server side of drone interface push system
|
||||
Fixed UUID '<' operator
|
||||
Added remote source pushing via drone protocol, remote sources
|
||||
now show up
|
||||
Added purging of virtual sources when drone connection is
|
||||
broken
|
||||
Dec 10 2005 devel Added UUID to drone protocol
|
||||
Added LocalChannelHop() to packetsources to prevent conflicts
|
||||
with virtual drone interfaces
|
||||
Fixed compilation of new packetsource framework on BSD
|
||||
Fixed div-by-0 on channel assignment to virtual stuff like
|
||||
drones
|
||||
Fixed breaking drones by always splitting interfaces in
|
||||
packetsource.h
|
||||
Dec 05 2005 devel Began to add remote drone virtual sources
|
||||
Wrote some documentation on the new PacketSource api
|
||||
Dec 04 2005 devel Major code drop:
|
||||
- Moved root IPC for channel control out of packetsourcetracker
|
||||
- Rewrote how packetsourcetracker and packetsources work entirely
|
||||
- Added UUID tracking of each source
|
||||
* This code drop is KNOWN TO BREAK on *BSD and on compiling
|
||||
drones! I wanted to get it off my drive and versioned,
|
||||
more updates later tonight.
|
||||
Fixed drone to use new packetsource framework
|
||||
Set wext packet sources to pull UUID node from the
|
||||
interface MAC address
|
||||
Ported BSDRT source to new packetsource framework (untested)
|
||||
Nov 19 2005 devel Fixed quirks in drone protocol
|
||||
Implemented standalone kismet_drone binary
|
||||
Nov 18 2005 devel Did beginnings of drone packet source & client framework
|
||||
Activated packetsource_drone (does nothing yet)
|
||||
Initial drone support usable
|
||||
Nov 17 2005 devel Added 'sourceopts' config line to set per-source special
|
||||
options ('fuzzycrypt' moved to here, added 'weakvalidate'
|
||||
to loosen frame header validation restrictions)
|
||||
Nov 16 2005 devel Fixed up error exporting to do _LOCAL | _FOO
|
||||
Added command parsing to drone server
|
||||
Activated drone server in kismet_server.cc
|
||||
Fixed drone server stupidity
|
||||
Nov 15 2005 devel Standardized some error reporting in netframe
|
||||
Started drone protocol rewrite
|
||||
Nov 13 2005 devel Fixed netframe fatal oops to match other code
|
||||
Added float mantissa components to util
|
||||
Added globalreg component for non-char getopt
|
||||
Nov 11 2005 devel Fixed filtercore compiling on systems without libpcre
|
||||
Fixed dual-registration of STRING protocl
|
||||
Nov 10 2005 devel Added string extraction (currently always on)
|
||||
Added PCRE string filtering
|
||||
Fixed PCRE negation tests
|
||||
Fixed filter examples to show "00:11:.." quoted mac strings
|
||||
Added STRINGS (0|1) and ADDSTRINGSFILTER commands to toggle
|
||||
string fetching
|
||||
Added string logfile (type 'string')
|
||||
Added alert logtile (type 'alert')
|
||||
Nov 08 2005 devel Added libpcre checks to configure
|
||||
Fixed util.cc compiling process title stuff
|
||||
Added basic lexer to util.cc
|
||||
Re-implemented MAC address filtering
|
||||
Added stubs for pcre filters
|
||||
Added PCRE filter string parsing
|
||||
Fixed infinite loop in linewrapper
|
||||
Added filter_netclient and PCRE execution for SSID filters
|
||||
Nov 07 2005 devel Fixed encryption/decryption check for data dissectors
|
||||
Nov 03 2005 devel Added smarter error message if the card drops out of monitor
|
||||
Oct 30 2005 devel Docs, plugin tweaks
|
||||
Oct 29 2005 devel Updated info text on header mode iwprivs on linux
|
||||
Added set_prismhdr to default wext set
|
||||
Oct 28 2005 devel Updated README.newcore
|
||||
Oct 26 2005 devel Turned on assorted packet sources (ipw2915, admtek, prism54g)
|
||||
Oct 25 2005 devel Added checking for *.bz2 *.gz files in logfile enumeration
|
||||
Revamped attaching alerts to packets so that more than one
|
||||
alert can be tracked
|
||||
Cleaned up nettxt export
|
||||
Added backlogged alerts to nettxt output per network
|
||||
Added fetching alert backlog to alertracker
|
||||
Oct 23 2005 devel Added client CDP port/dev tracking
|
||||
Added client XML output
|
||||
Fixed rampant client allocation bug
|
||||
Fixed negative bsstimestamp in netxml
|
||||
Fixed negative datasize, aggpoints in netxml
|
||||
Added nettxt dumpfile
|
||||
Oct 22 2005 devel Added export filter initialization to dumpfile core
|
||||
Fixed pcap references from copying pcap dump to gpsxml
|
||||
Added netxml dumpfile
|
||||
Added hooks for fetching const maps of netracker internals
|
||||
Oct 21 2005 devel Smartened up linewrap
|
||||
Oct 20 2005 devel Implemented shutdown&cleanup of root capsources via IPC
|
||||
Fixed ieee80211 linktype
|
||||
Oct 19 2005 devel Cosmetic - added IPC child process name control
|
||||
Ported sound controller to IPC framework
|
||||
Moved speech/sound spawn to after privdrop
|
||||
Removed gpsdclient from globalreg
|
||||
Oct 18 2005 devel Fixed invalid handling of map when cleaning up kisclient
|
||||
protocols during a disconnect
|
||||
Ported speech handler to IPC framework
|
||||
Oct 17 2005 devel Fixed packetsourcetracker not being updated for meta msgclient
|
||||
Removed packetsource_bsd stub class
|
||||
Moved packetsource_bsd to packetsource_bsdrt
|
||||
Fixed up IPC framework to a working state
|
||||
Ported packetsource root controller to IPC framework
|
||||
Oct 16 2005 devel Added tracker meta to packsources for chain components
|
||||
to access
|
||||
Added "monitor_mode" ioctl set attempt to generic
|
||||
monitor
|
||||
Fixed gpscore/gpsdclient double pollable registration
|
||||
Fixed gpsdclient parsing more
|
||||
Added void* aux pointer to message clients for incoming
|
||||
IPC_remote generic and other message clients linked to
|
||||
replication of messages (netframe)
|
||||
Added IPC generic framework (incomplete)
|
||||
Took drone/client/etc out of Makefile for now
|
||||
Oct 13 2005 devel Converted BSD interface control framework from stable
|
||||
Removed radiotap availability check, since we force it on
|
||||
with local headers now anyhow
|
||||
Fixed local radiotap inclusion
|
||||
Fleshed out BSD capture sources
|
||||
Added CRYPTODROP alert for networks dropping advertised
|
||||
encryption
|
||||
Changed network/client crypto tracking to take the last
|
||||
advertised crypto set instead of the aggregate of all
|
||||
crypto ever seen
|
||||
Added per-sec throttling to kismet.conf defaults
|
||||
Oct 12 2005 devel Tweaked configure for BSD radiotap detection
|
||||
Removed some OS specific stuff from generic pcapsource
|
||||
Removed -O2 from default makefile cxxflags (oops)
|
||||
Oct 10 2005 devel Removed wext22 check from configure (unneeded)
|
||||
Cleaned up more of the configure file
|
||||
Set auto-fail for missing wext headers on linux
|
||||
Changed config warning for disabling wext
|
||||
Removed netlink socket checking from configure
|
||||
Oct 09 2005 devel Started adding failure conditions to autoconf and forcing
|
||||
explicit disabling of expected components (like ncurses)
|
||||
which is the "right" thing to do.
|
||||
Removed some linux-specific stuff from the radiotap header,
|
||||
renamed it to local_radiotap_header.h
|
||||
Oct 06 2005 devel Removed double-cache-lookup in NETWORK protocol handler
|
||||
Removed double-cache-lookup in CLIENT protocol handler
|
||||
Oct 04 2005 devel Moved versioning into header file for plugins to draw
|
||||
from
|
||||
Removed the timestamp file and zeroed out the timestamp
|
||||
element in the protocol. This should have been done
|
||||
a long time ago.
|
||||
Sep 29 2005 devel Various BSD related fixups, buffer size checks
|
||||
Added libdl check to autoconf (for BSD systems)
|
||||
Sep 26 2005 devel Moved dirty network and client tracking into vector, fixed
|
||||
constantly sending networks
|
||||
Sep 21 2005 devel Split GPS into gpscore and gpsdclient in anticipation of
|
||||
adding additional GPS capture methods
|
||||
Sep 20 2005 devel Implemented INFO protocol, added additional fields,
|
||||
deprecated 'signal' field
|
||||
Fixed maxsignal initialization in SNR fields
|
||||
Sep 19 2005 devel Fixed config file cmdline option
|
||||
Finished redoing CARD protocol
|
||||
Fixed stupid error in gpsxml logging
|
||||
Sep 18 2005 devel Moved CARD protocol into packetsourcetracker
|
||||
Fixed "client ring buffer full" message going into the
|
||||
client ring buffer
|
||||
Fixed loop in clinetframe kill procedure, fixed hammering
|
||||
"Socket closed" error messages
|
||||
Fixed gpsd reconnect if nothing to connect to
|
||||
Sep 17 2005 devel Added tracking of multiple SSIDs per network, and tracking
|
||||
all networks a client has probed for. No methods to export
|
||||
this information yet.
|
||||
Added removal abilities for client commands and network
|
||||
protocols in netframe
|
||||
Added auxptr to network protocols for enable functions to
|
||||
hook a class
|
||||
Added plugin listing protocol
|
||||
Added plugin shutdown
|
||||
Put plugintracker in globalreg
|
||||
Sep 15 2005 devel Added user plugin directory scanning and loading
|
||||
Implemented actually kickstarting the plugins
|
||||
Made better errors for dlopen() being stupid
|
||||
Fixed plugin symbol exporting
|
||||
Wrote demo NULL plugin (crappy example, better to come)
|
||||
Plugins should now be functional. YOU WILL NEED TO RERUN
|
||||
CONFIGURE for plugins to enable properly, you will also
|
||||
need to turn on 'allowplugins=true' in your config file.
|
||||
Sep 14 2005 devel Imported -stable autoconf with all its little fixes
|
||||
Added LIB_LOC to config.h
|
||||
Fixed config.h.bot glitch
|
||||
Changed privdrop behavior to keep running when there is a
|
||||
user/target mismatch provided neither is root, and kismet
|
||||
isn't started as root. (ie, Kismet configured to drop to
|
||||
'bob', started as 'susan', now runs as 'susan' with an
|
||||
error warning)
|
||||
Added linewrap to fataloutput message client
|
||||
Added plugin core (funny how small a note that is) and
|
||||
started plugin loaders
|
||||
Sep 12 2005 devel Added per-network and per-client packet rate data
|
||||
Added packetrate fields to NETWORK and CLIENT protos
|
||||
Sep 11 2005 devel Turned on hostap (straight 'mode foo' control, no priv
|
||||
monitor)
|
||||
Started new filter core class
|
||||
Added filtering to netracker for filter_tracker
|
||||
Removed 'FILTER' packetchain stage since it's not going to
|
||||
be used that way
|
||||
Fixed AVS handling
|
||||
Fixed class overload of fcsbytes causing all sorts of issues
|
||||
Fixed some errors with compiling with suid disabled
|
||||
Added ADDTRACKERFILTER client command to nettracker
|
||||
Sep 10 2005 devel Turned on ipw2100 source again
|
||||
Turned on acx100 source (kluge to hopefully work with
|
||||
modern acx100 drivers)
|
||||
Turned on atmel-usb sourceA
|
||||
Turned on rt2400, rt2500, rt8180
|
||||
Sep 09 2005 devel Started implementing 'auto' device support
|
||||
Skeleton of 'auto' capsource in place (for the one capsource
|
||||
newcore supports currently)
|
||||
Added Madwifi capsource back
|
||||
Sep 08 2005 devel Added BCASTDISCON and AIRJACKSSID alerts
|
||||
Sep 07 2005 devel Fixed client/server protocol caching
|
||||
Added probereq SSID tracking
|
||||
Added tracked network type updating
|
||||
Changed timestamp/timetracker set/tick to head of loop
|
||||
Added 'retry' flag to ieee80211 packet info
|
||||
Added fragments/retries tracking
|
||||
Added fragments and retries to CLIENT and NETWORK protocols
|
||||
Fixed CLIENT protocol enable
|
||||
Added CLIENT to nettracker tick
|
||||
Sep 06 2005 devel Added some support for flooding clients with more than the
|
||||
ringbuf can handle
|
||||
Sep 05 2005 devel Fixed DHCP handling
|
||||
Fixed UDP handling
|
||||
Fixed packetchain ordering
|
||||
Added IP tracking
|
||||
Fixed network/client packet attachments
|
||||
Sep 04 2005 devel Started adding data processing, IP guessing
|
||||
Added DHCPCONFLICT alert to catch multiple DHCP servers
|
||||
on one network. Maybe a little too layer-3ish
|
||||
Added CDP ids to NETWORK protocol
|
||||
Added client creation and association
|
||||
Sep 03 2005 devel Fixed CDP processing
|
||||
Sep 02 2005 devel Fixed alert on channel 0 networks getting a channel
|
||||
Fixed treating probe req, disassoc, auth, and death as
|
||||
frames that have a normal fixparm
|
||||
Fixed IAPP handling
|
||||
Added CDP support (untested)
|
||||
Sep 01 2005 devel Added timer kick to netracker to push network updates to
|
||||
kismet clients
|
||||
Fixed numerous uses of unitialzed memory
|
||||
Fixed gaping memory leakage due to destructor inheritance
|
||||
Aug 31 2005 devel Added WEP decryptor, MANGLE packet element, updated pcap
|
||||
and tun loggers to write the mangled frame
|
||||
Added Adler-32 checksum to util.[h|cc]
|
||||
Added bsstimestamp network field
|
||||
Fixed gpsd adding null data to each frame
|
||||
Fixed turbocell nid returning \001 buffered crap
|
||||
Fixed newcore server working with existing client
|
||||
Aug 29 2005 devel Added writeinterval support
|
||||
Aug 27 2005 devel Added auxptr to client command pointers
|
||||
Moved wepkey code into private functions in kisbuiltindis
|
||||
Aug 26 2005 devel Moved wepkey loading code and network protocols into
|
||||
packetdissectors.cc/kisbuiltindissector
|
||||
Aug 25 2005 devel Data dissector cleanup, merged packinfo crypset into data
|
||||
Aug 24 2005 devel Added constants for IAPP/other data sizes
|
||||
Added ARP ip dissector, generic IP dissector
|
||||
Added IAPP dissector (untested)
|
||||
Added DHCP dissector (untested)
|
||||
Added ISAKMP dissector (untested)
|
||||
Aug 23 2005 devel Added 16/32/64 bit ptr extractor
|
||||
Added EAP data detection (untested)
|
||||
Aug 22 2005 devel Fixed opening tcpserver before channel child
|
||||
Moved packet dissectors into helper class
|
||||
Moved packet registration and alert stuff into dissector
|
||||
helper class
|
||||
Added data dissection framework
|
||||
Added lucent signatures/detection/alert
|
||||
Aug 20 2005 devel Fixed alerts again (parsing enable lines)
|
||||
Restored '-s/--silent' cmd line option for server
|
||||
Implemented --help and cross-module --help output
|
||||
Aug 19 2005 devel Fixed some header wonkiness
|
||||
Started implementing alert framework (mostly there)
|
||||
Added alert rate parsing from config files
|
||||
Added --no-line-wrap for grep behavior
|
||||
Fixed alerts
|
||||
Activated channel change network alert
|
||||
Aug 18 2005 devel Restored WPA tag dissection from stable
|
||||
Fixed over-aggressive "new network detected"
|
||||
Added linewrap to stdout text and fixed linewrap code
|
||||
boundary checks, made linewrap word length relational
|
||||
Added extended supported rates support
|
||||
Aug 17 2005 devel Started implementing server protocol generic caching to
|
||||
eliminate the use of crummy vector converts of the entire
|
||||
struct
|
||||
Began enabling netracker NETWORK protocol
|
||||
Finished netracker NETWORK protocol rewrite
|
||||
Finished netracker CLIENT protocol rewrite
|
||||
Aug 14 2005 devel Added tun/tap virtual interface support for sharing packets
|
||||
Added patches/ dir and linux kernel patch for tuntap
|
||||
Fixed stupid timing inversion on channel hop
|
||||
Aug 13 2005 devel Resumed use of CHANGELOG file for newcore development as it
|
||||
is finally on its feet enough
|
||||
Added GPS-only packetchain data injection to gpsdclient
|
||||
Moved startup time and current timestamp to timetracker
|
||||
Changed global timestamp to usec precision
|
||||
Added GPSXML dumpfile module
|
||||
Change dumpfile superclass dumpfile name generation
|
||||
Added Flush() to dumpfile superclass and subs
|
||||
Added README.newcore
|
||||
Fixed gpsd parsing of \0 characters
|
||||
Fixed closing dumpfiles
|
||||
Echo client command errors to messagebus
|
||||
Added placeholder WEP field for clients
|
||||
Started phasing out broken protocol references to
|
||||
tracktypes networks, commented out network protocols
|
||||
for now
|
||||
--- -- ---- ----- Newcore changelog started
|
|
@ -1,347 +0,0 @@
|
|||
** UNLESS OTHERWISE NOTED IN THE FILE OR DIRECTORY, KISMET
|
||||
IS RELEASED UNDER THE GPL2 LICENSE
|
||||
|
||||
SPECIFIC SUBCOMPONENTS AND FILES MAY BE UNDER LESS RESTRICTIVE
|
||||
LICENSES. THESE DIFFERENCES ARE NOTED IN THE FILE OR IN THE
|
||||
LICENSE FILE OF THOSE SUBDIRECTORIES **
|
||||
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
|
@ -1,618 +0,0 @@
|
|||
include Makefile.inc
|
||||
|
||||
CONFIGFILES = \
|
||||
kismet.conf \
|
||||
kismet_httpd.conf \
|
||||
kismet_alerts.conf \
|
||||
kismet_memory.conf \
|
||||
kismet_storage.conf \
|
||||
kismet_logging.conf \
|
||||
kismet_filter.conf \
|
||||
kismet_uav.conf \
|
||||
kismet_80211.conf
|
||||
|
||||
# Parsers (modeled on former Kaitai model)
|
||||
PARSERS = \
|
||||
dot11_parsers/dot11_ie.cc.o \
|
||||
dot11_parsers/dot11_ie_7_country.cc.o \
|
||||
dot11_parsers/dot11_ie_11_qbss.cc.o \
|
||||
dot11_parsers/dot11_ie_33_power.cc.o \
|
||||
dot11_parsers/dot11_ie_36_supported_channels.cc.o \
|
||||
dot11_parsers/dot11_ie_45_ht_cap.cc.o \
|
||||
dot11_parsers/dot11_ie_48_rsn.cc.o \
|
||||
dot11_parsers/dot11_ie_52_rmm_neighbor.cc.o \
|
||||
dot11_parsers/dot11_ie_54_mobility.cc.o \
|
||||
dot11_parsers/dot11_ie_55_fastbss.cc.o \
|
||||
dot11_parsers/dot11_ie_61_ht_op.cc.o \
|
||||
dot11_parsers/dot11_ie_70_rm_capabilities.cc.o \
|
||||
dot11_parsers/dot11_ie_133_cisco_ccx.cc.o \
|
||||
dot11_parsers/dot11_ie_150_vendor.cc.o \
|
||||
dot11_parsers/dot11_ie_150_cisco_powerlevel.cc.o \
|
||||
dot11_parsers/dot11_ie_191_vht_cap.cc.o \
|
||||
dot11_parsers/dot11_ie_192_vht_op.cc.o \
|
||||
dot11_parsers/dot11_ie_127_extended_capabilities.cc.o \
|
||||
dot11_parsers/dot11_ie_221_vendor.cc.o \
|
||||
dot11_parsers/dot11_ie_221_ms_wps.cc.o \
|
||||
dot11_parsers/dot11_ie_221_ms_wmm.cc.o \
|
||||
dot11_parsers/dot11_ie_221_dji_droneid.cc.o \
|
||||
dot11_parsers/dot11_ie_221_wfa_wpa.cc.o \
|
||||
dot11_parsers/dot11_ie_221_cisco_client_mfp.cc.o \
|
||||
dot11_parsers/dot11_ie_221_wpa_transition.cc.o \
|
||||
dot11_parsers/dot11_ie_221_rsn_pmkid.cc.o \
|
||||
dot11_parsers/dot11_ie_255_ext_tag.cc.o \
|
||||
dot11_parsers/dot11_action.cc.o \
|
||||
dot11_parsers/dot11_wpa_eap.cc.o \
|
||||
bluetooth_parsers/bt_rfinfo.cc.o
|
||||
|
||||
# To prevent a deps problem, we define these targets via autoconf to reference
|
||||
# the variable setting the list
|
||||
PROTOBUF_CPP_O_TARGET = @PROTOBUF_CPP_O_TARGET@
|
||||
PROTOBUF_CPP_O = \
|
||||
protobuf_cpp/kismet.pb.cc.o \
|
||||
protobuf_cpp/http.pb.cc.o \
|
||||
protobuf_cpp/datasource.pb.cc.o \
|
||||
protobuf_cpp/linuxbluetooth.pb.cc.o
|
||||
|
||||
PROTOBUF_CPP_H_TARGET = @PROTOBUF_CPP_H_TARGET@
|
||||
PROTOBUF_CPP_H = \
|
||||
protobuf_cpp/kismet.pb.h \
|
||||
protobuf_cpp/http.pb.h \
|
||||
protobuf_cpp/datasource.pb.h \
|
||||
protobuf_cpp/linuxbluetooth.pb.h
|
||||
|
||||
PROTOBUF_C_O = \
|
||||
protobuf_c/kismet.pb-c.c.o \
|
||||
protobuf_c/datasource.pb-c.c.o \
|
||||
protobuf_c/linuxbluetooth.pb-c.c.o
|
||||
|
||||
PROTOBUF_C_H = \
|
||||
protobuf_c/kismet.pb-c.h \
|
||||
protobuf_c/datasource.pb-c.h \
|
||||
protobuf_c/linuxbluetooth.pb-c.h
|
||||
|
||||
|
||||
# Common pure-c code for capturesource binaries
|
||||
DATASOURCE_COMMON_C_O = \
|
||||
$(PROTOBUF_C_O) \
|
||||
simple_ringbuf_c.c.o capture_framework.c.o
|
||||
DATASOURCE_COMMON_A = libkismetdatasource.a
|
||||
|
||||
CAPTURE_PCAPFILE_O = \
|
||||
capture_pcapfile.c.o
|
||||
CAPTURE_PCAPFILE = kismet_cap_pcapfile
|
||||
BUILD_CAPTURE_PCAPFILE = @BUILD_CAPTURE_PCAPFILE@
|
||||
|
||||
CAPTURE_KISMETDB_O = \
|
||||
capture_kismetdb.c.o
|
||||
CAPTURE_KISMETDB = kismet_cap_kismetdb
|
||||
BUILD_CAPTURE_KISMETDB = @BUILD_CAPTURE_KISMETDB@
|
||||
|
||||
CAPTURE_LINUX_WIFI = capture_linux_wifi/kismet_cap_linux_wifi
|
||||
BUILD_CAPTURE_LINUX_WIFI = @BUILD_CAPTURE_LINUX_WIFI@
|
||||
|
||||
CAPTURE_HACKRF_SWEEP_O = \
|
||||
capture_hackrf_sweep.c.o
|
||||
CAPTURE_HACKRF_SWEEP = kismet_cap_hackrf_sweep
|
||||
BUILD_CAPTURE_HACKRF_SWEEP = @BUILD_CAPTURE_HACKRF_SWEEP@
|
||||
|
||||
CAPTURE_LINUX_BLUETOOTH = capture_linux_bluetooth/kismet_cap_linux_bluetooth
|
||||
BUILD_CAPTURE_LINUX_BLUETOOTH = @BUILD_CAPTURE_LINUX_BLUETOOTH@
|
||||
|
||||
CAPTURE_OSX_COREWLAN = capture_osx_corewlan_wifi/kismet_cap_osx_corewlan_wifi
|
||||
BUILD_CAPTURE_OSX_COREWLAN = @BUILD_CAPTURE_OSX_COREWLAN@
|
||||
|
||||
CAPTURE_SDR_RTL433 = capture_sdr_rtl433/kismet_cap_sdr_rtl433
|
||||
BUILD_CAPTURE_SDR_RTL433 = @BUILD_CAPTURE_SDR_RTL433@
|
||||
|
||||
CAPTURE_SDR_RTLAMR = capture_sdr_rtlamr/kismet_cap_sdr_rtlamr
|
||||
BUILD_CAPTURE_SDR_RTLAMR = @BUILD_CAPTURE_SDR_RTLAMR@
|
||||
|
||||
CAPTURE_SDR_RTLADSB = capture_sdr_rtladsb/kismet_cap_sdr_rtladsb
|
||||
BUILD_CAPTURE_SDR_RTLADSB = @BUILD_CAPTURE_SDR_RTLADSB@
|
||||
|
||||
CAPTURE_FREAKLABS_ZIGBEE = capture_freaklabs_zigbee/kismet_cap_freaklabs_zigbee
|
||||
BUILD_CAPTURE_FREAKLABS_ZIGBEE = @BUILD_CAPTURE_FREAKLABS_ZIGBEE@
|
||||
|
||||
CAPTURE_NRF_MOUSEJACK = capture_nrf_mousejack/kismet_cap_nrf_mousejack
|
||||
BUILD_CAPTURE_NRF_MOUSEJACK = @BUILD_CAPTURE_NRF_MOUSEJACK@
|
||||
|
||||
# Capture binaries to build
|
||||
DATASOURCE_BINS = @DATASOURCE_BINS@
|
||||
|
||||
LOGTOOL_KISMETDB_STRIP = log_tools/kismetdb_strip_packets
|
||||
|
||||
LOGTOOL_KISMETDB_WIGLE = log_tools/kismetdb_to_wiglecsv
|
||||
LOGTOOL_KISMETDB_WIGLE_O = \
|
||||
log_tools/kismetdb_to_wiglecsv.cc.o \
|
||||
sqlite3_cpp11.cc.o jsoncpp.cc.o
|
||||
|
||||
LOGTOOL_KISMETDB_JSON = log_tools/kismetdb_dump_devices
|
||||
LOGTOOL_KISMETDB_JSON_O = \
|
||||
log_tools/kismetdb_dump_devices.cc.o \
|
||||
sqlite3_cpp11.cc.o
|
||||
|
||||
LOGTOOL_KISMETDB_STATS = log_tools/kismetdb_statistics
|
||||
LOGTOOL_KISMETDB_STATS_O = \
|
||||
log_tools/kismetdb_statistics.cc.o \
|
||||
sqlite3_cpp11.cc.o jsoncpp.cc.o
|
||||
|
||||
LOGTOOL_BINS = \
|
||||
$(LOGTOOL_KISMETDB_STRIP) \
|
||||
$(LOGTOOL_KISMETDB_WIGLE) \
|
||||
$(LOGTOOL_KISMETDB_JSON) \
|
||||
$(LOGTOOL_KISMETDB_STATS)
|
||||
|
||||
# Disabled; Kaitai generates unusable C++ code currently
|
||||
# KAITAI_PARSERS = \
|
||||
# kaitai_parsers/wpaeap.cc.o \
|
||||
# kaitai_parsers/dot11_ie.cc.o \
|
||||
# kaitai_parsers/dot11_action.cc.o \
|
||||
# kaitai_parsers/dot11_ie_7_country.cc.o \
|
||||
# kaitai_parsers/dot11_ie_11_qbss.cc.o \
|
||||
# kaitai_parsers/dot11_ie_45_ht.cc.o \
|
||||
# kaitai_parsers/dot11_ie_48_rsn.cc.o \
|
||||
# kaitai_parsers/dot11_ie_48_rsn_partial.cc.o \
|
||||
# kaitai_parsers/dot11_ie_52_rmm_neighbor.cc.o \
|
||||
# kaitai_parsers/dot11_ie_54_mobility.cc.o \
|
||||
# kaitai_parsers/dot11_ie_61_ht.cc.o \
|
||||
# kaitai_parsers/dot11_ie_133_cisco_ccx.cc.o \
|
||||
# kaitai_parsers/dot11_ie_191_vht_capabilities.cc.o \
|
||||
# kaitai_parsers/dot11_ie_192_vht_operation.cc.o \
|
||||
# kaitai_parsers/dot11_ie_221_vendor.cc.o \
|
||||
# kaitai_parsers/dot11_ie_221_ms_wps.cc.o \
|
||||
# kaitai_parsers/dot11_ie_221_ms_wmm.cc.o \
|
||||
# kaitai_parsers/dot11_ie_221_dji_droneid.cc.o \
|
||||
# kaitai_parsers/dot11_ie_221_wfa_wpa.cc.o
|
||||
|
||||
PSO = util.cc.o macaddr.cc.o uuid.cc.o xxhash.cc.o boost_like_hash.cc.o sqlite3_cpp11.cc.o \
|
||||
globalregistry.cc.o eventbus.cc.o \
|
||||
pollabletracker.cc.o ringbuf2.cc.o chainbuf.cc.o filewritebuf.cc.o buffer_handler.cc.o \
|
||||
packet.cc.o messagebus.cc.o configfile.cc.o getopt.cc.o \
|
||||
psutils.cc.o battery.cc.o \
|
||||
tcpserver2.cc.o tcpclient2.cc.o serialclient2.cc.o pipeclient.cc.o ipc_remote2.cc.o \
|
||||
$(PROTOBUF_CPP_O_TARGET) kis_external.cc.o \
|
||||
dlttracker.cc.o antennatracker.cc.o datasourcetracker.cc.o kis_datasource.cc.o \
|
||||
datasource_linux_bluetooth.cc.o datasource_rtl433.cc.o datasource_rtlamr.cc.o datasource_rtladsb.cc.o \
|
||||
kis_net_microhttpd.cc.o kis_net_microhttpd_handlers.cc.o system_monitor.cc.o base64.cc.o \
|
||||
kis_httpd_websession.cc.o kis_httpd_registry.cc.o \
|
||||
gpstracker.cc.o kis_gps.cc.o gpsnmea.cc.o gpsserial2.cc.o gpstcp.cc.o \
|
||||
gpsgpsd2.cc.o gpsfake.cc.o gpsweb.cc.o \
|
||||
packetchain.cc.o packet_filter.cc.o class_filter.cc.o \
|
||||
trackedelement.cc.o trackedcomponent.cc.o entrytracker.cc.o \
|
||||
trackedlocation.cc.o devicetracker_component.cc.o \
|
||||
devicetracker_view.cc.o devicetracker_view_workers.cc.o \
|
||||
jsoncpp.cc.o json_adapter.cc.o \
|
||||
plugintracker.cc.o alertracker.cc.o timetracker.cc.o channeltracker2.cc.o \
|
||||
devicetracker.cc.o devicetracker_workers.cc.o devicetracker_httpd.cc.o \
|
||||
kis_dlt.cc.o kis_dlt_ppi.cc.o kis_dlt_radiotap.cc.o \
|
||||
kaitaistream.cc.o \
|
||||
$(PARSERS) \
|
||||
phy_80211.cc.o phy_80211_components.cc.o phy_80211_dissectors.cc.o \
|
||||
phy_rtl433.cc.o phy_rtlamr.cc.o phy_rtladsb.cc.o phy_zwave.cc.o \
|
||||
phy_bluetooth.cc.o phy_uav_drone.cc.o phy_nrf_mousejack.cc.o \
|
||||
dot11_fingerprint.cc.o kis_dissector_ipdata.cc.o \
|
||||
manuf.cc.o \
|
||||
logtracker.cc.o kis_ppilogfile.cc.o kis_databaselogfile.cc.o kis_pcapnglogfile.cc.o \
|
||||
messagebus_restclient.cc.o \
|
||||
streamtracker.cc.o \
|
||||
pcapng_stream_ringbuf.cc.o streambuf_stream_buffer.cc.o \
|
||||
devicetracker_httpd_pcap.cc.o phy_80211_httpd_pcap.cc.o \
|
||||
kis_database.cc.o storageloader.cc.o \
|
||||
kismet_server.cc.o
|
||||
|
||||
PS = kismet
|
||||
|
||||
STD_ALL = Makefile $(PS) $(DATASOURCE_BINS) $(LOGTOOL_BINS)
|
||||
DS_ONLY = Makefile $(DATASOURCE_BINS)
|
||||
|
||||
ALL = @ALLTARGETS@
|
||||
|
||||
INSTBINS = $(PS) $(DATASOURCE_BINS) $(LOGTOOL_BINS)
|
||||
|
||||
all: $(ALL)
|
||||
|
||||
all-with-plugins:
|
||||
@make plugins-clean
|
||||
@make all
|
||||
@make plugins
|
||||
|
||||
# Autogen the version file
|
||||
version.c: FORCE
|
||||
@{ $(GIT) rev-parse --short HEAD 2>/dev/null || echo "non-git-release"; } | awk ' BEGIN {print "#include \"version.h\""} {print "const char *VERSION_GIT_COMMIT = \"" $$0"\";"} END {}' > version.c
|
||||
@date | awk 'BEGIN {} {print "const char *VERSION_BUILD_TIME = \""$$0"\";"} END {} ' >> version.c
|
||||
|
||||
# Force remove version.c.o since it's left behind owned by root as part of suidinstall, which screws
|
||||
# up a lot of builds for people; we assume we can `rm -f` it
|
||||
version.c.o : version.c version.c.d
|
||||
@rm -f version.c.o
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c version.c -o version.c.o
|
||||
|
||||
$(PS): $(PROTOBUF_CPP_O_TARGET) $(PROTOBUF_CPP_H_TARGET) $(PSO) $(patsubst %c.o,%c.d,$(PSO)) version.c.o
|
||||
$(LD) $(LDFLAGS) -o $(PS) $(PSO) version.c.o $(LIBS) $(CXXLIBS) $(PCAPLIBS) $(KSLIBS) -rdynamic
|
||||
|
||||
$(LOGTOOL_KISMETDB_STRIP): log_tools/kismetdb_strip_packet_content.c.o log_tools/kismetdb_strip_packet_content.c.d
|
||||
$(CC) $(LDFLAGS) -o $(LOGTOOL_KISMETDB_STRIP) log_tools/kismetdb_strip_packet_content.c.o -lsqlite3
|
||||
|
||||
$(LOGTOOL_KISMETDB_WIGLE): $(LOGTOOL_KISMETDB_WIGLE_O) $(patsubst %c.o,%c.d,$(LOGTOOL_KISMETDB_WIGLE_O))
|
||||
$(LD) $(LDFLAGS) -o $(LOGTOOL_KISMETDB_WIGLE) $(LOGTOOL_KISMETDB_WIGLE_O) $(LIBS) $(CXXLIBS) -rdynamic
|
||||
|
||||
$(LOGTOOL_KISMETDB_JSON): $(LOGTOOL_KISMETDB_JSON_O) $(patsubst %c.o,%c.d,$(LOGTOOL_KISMETDB_JSON_O))
|
||||
$(LD) $(LDFLAGS) -o $(LOGTOOL_KISMETDB_JSON) $(LOGTOOL_KISMETDB_JSON_O) $(LIBS) $(CXXLIBS) -rdynamic
|
||||
|
||||
$(LOGTOOL_KISMETDB_STATS): $(LOGTOOL_KISMETDB_STATS_O) $(patsubst %c.o,%c.d,$(LOGTOOL_KISMETDB_STATS_O))
|
||||
$(LD) $(LDFLAGS) -o $(LOGTOOL_KISMETDB_STATS) $(LOGTOOL_KISMETDB_STATS_O) $(LIBS) $(CXXLIBS) -rdynamic
|
||||
|
||||
$(DATASOURCE_COMMON_A): $(PROTOBUF_C_O) $(PROTOBUF_C_H) $(DATASOURCE_COMMON_C_O)
|
||||
$(AR) rcs $(DATASOURCE_COMMON_A) $(DATASOURCE_COMMON_C_O)
|
||||
|
||||
$(CAPTURE_PCAPFILE): $(PROTOBUF_C_H) $(DATASOURCE_COMMON_A) $(CAPTURE_PCAPFILE_O)
|
||||
$(CC) $(LDFLAGS) -o $(CAPTURE_PCAPFILE) $(CAPTURE_PCAPFILE_O) $(DATASOURCE_COMMON_A) $(PCAPLIBS) $(DATASOURCE_LIBS)
|
||||
|
||||
$(CAPTURE_KISMETDB): $(PROTOBUF_C_H) $(DATASOURCE_COMMON_A) $(CAPTURE_KISMETDB_O)
|
||||
$(CC) $(LDFLAGS) -o $(CAPTURE_KISMETDB) $(CAPTURE_KISMETDB_O) $(DATASOURCE_COMMON_A) $(DATASOURCE_LIBS) -lsqlite3
|
||||
|
||||
$(CAPTURE_LINUX_WIFI): $(PROTOBUF_C_H) $(DATASOURCE_COMMON_A) FORCE
|
||||
(cd capture_linux_wifi && $(MAKE))
|
||||
|
||||
$(CAPTURE_LINUX_BLUETOOTH): $(PROTOBUF_C_H) $(DATASOURCE_COMMON_A) FORCE
|
||||
(cd capture_linux_bluetooth && $(MAKE))
|
||||
|
||||
$(CAPTURE_OSX_COREWLAN): $(PROTOBUF_C_H) $(DATASOURCE_COMMON_A) FORCE
|
||||
(cd capture_osx_corewlan_wifi && $(MAKE))
|
||||
|
||||
$(CAPTURE_SDR_RTL433): FORCE
|
||||
(cd capture_sdr_rtl433 && $(MAKE))
|
||||
|
||||
$(CAPTURE_SDR_RTLAMR): FORCE
|
||||
(cd capture_sdr_rtlamr && $(MAKE))
|
||||
|
||||
$(CAPTURE_SDR_RTLADSB): FORCE
|
||||
(cd capture_sdr_rtladsb && $(MAKE))
|
||||
|
||||
$(CAPTURE_HACKRF_SWEEP): $(PROTOBUF_C_H) $(DATASOURCE_COMMON_A) $(CAPTURE_HACKRF_SWEEP_O)
|
||||
$(CC) $(LDFLAGS) -o $(CAPTURE_HACKRF_SWEEP) $(CAPTURE_HACKRF_SWEEP_O) $(DATASOURCE_COMMON_A) -lhackrf -lfftw3 $(LIBMLIB) -lpthread -lm
|
||||
|
||||
$(CAPTURE_NRF_MOUSEJACK): $(PROTOBUF_C_H) $(DATASOURCE_COMMON_A) FORCE
|
||||
(cd capture_nrf_mousejack && $(MAKE))
|
||||
|
||||
$(CAPTURE_FREAKLABS_ZIGBEE): FORCE
|
||||
(cd capture_freaklabs_zigbee && $(MAKE))
|
||||
|
||||
FORCE:
|
||||
|
||||
datasources: $(DATASOURCE_BINS)
|
||||
|
||||
Makefile: Makefile.in configure
|
||||
@-echo "'Makefile.in' or 'configure' are more current than this Makefile. You should re-run 'configure'."
|
||||
|
||||
binsuidinstall: $(DATASOURCE_BINS)
|
||||
mkdir -p $(BIN)
|
||||
|
||||
@if test "$(BUILD_CAPTURE_LINUX_WIFI)"x = "1"x; then \
|
||||
$(INSTALL) -o $(INSTUSR) -g $(SUIDGROUP) -m 4550 $(CAPTURE_LINUX_WIFI) $(BIN)/`basename $(CAPTURE_LINUX_WIFI)`; \
|
||||
fi;
|
||||
|
||||
@if test "$(BUILD_CAPTURE_LINUX_BLUETOOTH)"x = "1"x; then \
|
||||
$(INSTALL) -o $(INSTUSR) -g $(SUIDGROUP) -m 4550 $(CAPTURE_LINUX_BLUETOOTH) $(BIN)/`basename $(CAPTURE_LINUX_BLUETOOTH)`; \
|
||||
fi;
|
||||
|
||||
@if test "$(BUILD_CAPTURE_OSX_COREWLAN)"x = "1"x; then \
|
||||
$(INSTALL) -o $(INSTUSR) -g $(SUIDGROUP) -m 4550 $(CAPTURE_OSX_COREWLAN) $(BIN)/`basename $(CAPTURE_OSX_COREWLAN)`; \
|
||||
fi;
|
||||
|
||||
@if test "$(BUILD_CAPTURE_NRF_MOUSEJACK)"x = "1"x; then \
|
||||
$(INSTALL) -o $(INSTUSR) -g $(SUIDGROUP) -m 4550 $(CAPTURE_NRF_MOUSEJACK) $(BIN)/`basename $(CAPTURE_NRF_MOUSEJACK)`; \
|
||||
fi;
|
||||
|
||||
commoninstall: $(INSTBINS)
|
||||
mkdir -p $(ETC)
|
||||
mkdir -p $(BIN)
|
||||
|
||||
$(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 555 $(PS) $(BIN)/$(PS);
|
||||
|
||||
# Install the alias script
|
||||
$(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 555 kismet_server $(BIN)/kismet_server;
|
||||
|
||||
# Install the compiled log tools
|
||||
$(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 555 $(LOGTOOL_KISMETDB_STRIP) $(BIN)/`basename $(LOGTOOL_KISMETDB_STRIP)`;
|
||||
$(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 555 $(LOGTOOL_KISMETDB_JSON) $(BIN)/`basename $(LOGTOOL_KISMETDB_JSON)`;
|
||||
$(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 555 $(LOGTOOL_KISMETDB_WIGLE) $(BIN)/`basename $(LOGTOOL_KISMETDB_WIGLE)`;
|
||||
$(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 555 $(LOGTOOL_KISMETDB_STATS) $(BIN)/`basename $(LOGTOOL_KISMETDB_STATS)`;
|
||||
|
||||
mkdir -p $(BIN)
|
||||
|
||||
@if test "$(BUILD_CAPTURE_PCAPFILE)"x = "1"x; then \
|
||||
$(INSTALL) -o $(INSTUSR) -g $(INSTGRP) $(CAPTURE_PCAPFILE) $(BIN)/$(CAPTURE_PCAPFILE); \
|
||||
fi;
|
||||
|
||||
@if test "$(BUILD_CAPTURE_KISMETDB)"x = "1"x; then \
|
||||
$(INSTALL) -o $(INSTUSR) -g $(INSTGRP) $(CAPTURE_KISMETDB) $(BIN)/$(CAPTURE_KISMETDB); \
|
||||
fi;
|
||||
|
||||
@if test "$(BUILD_CAPTURE_LINUX_WIFI)"x = "1"x; then \
|
||||
$(INSTALL) -o $(INSTUSR) -g $(INSTGRP) $(CAPTURE_LINUX_WIFI) $(BIN)/`basename $(CAPTURE_LINUX_WIFI)`; \
|
||||
fi;
|
||||
|
||||
@if test "$(BUILD_CAPTURE_LINUX_BLUETOOTH)"x = "1"x; then \
|
||||
$(INSTALL) -o $(INSTUSR) -g $(INSTGRP) $(CAPTURE_LINUX_BLUETOOTH) $(BIN)/`basename $(CAPTURE_LINUX_BLUETOOTH)`; \
|
||||
fi;
|
||||
|
||||
@if test "$(BUILD_CAPTURE_OSX_COREWLAN)"x = "1"x; then \
|
||||
$(INSTALL) -o $(INSTUSR) -g $(SUIDGROUP) $(CAPTURE_OSX_COREWLAN) $(BIN)/`basename $(CAPTURE_OSX_COREWLAN)`; \
|
||||
fi;
|
||||
|
||||
@if test "$(BUILD_CAPTURE_HACKRF_SWEEP)"x = "1"x; then \
|
||||
$(INSTALL) -o $(INSTUSR) -g $(INSTGRP) $(CAPTURE_HACKRF_SWEEP) $(BIN)/$(CAPTURE_HACKRF_SWEEP); \
|
||||
fi;
|
||||
|
||||
@if test "$(BUILD_CAPTURE_NRF_MOUSEJACK)"x = "1"x; then \
|
||||
$(INSTALL) -o $(INSTUSR) -g $(INSTGRP) $(CAPTURE_NRF_MOUSEJACK) $(BIN)/`basename $(CAPTURE_NRF_MOUSEJACK)`; \
|
||||
fi;
|
||||
|
||||
@if test "$(BUILD_CAPTURE_SDR_RTL433)"x = "1"x; then \
|
||||
(cd capture_sdr_rtl433 && $(MAKE) install) \
|
||||
fi;
|
||||
|
||||
@if test "$(BUILD_CAPTURE_SDR_RTLAMR)"x = "1"x; then \
|
||||
(cd capture_sdr_rtlamr && $(MAKE) install) \
|
||||
fi;
|
||||
|
||||
@if test "$(BUILD_CAPTURE_SDR_RTLADSB)"x = "1"x; then \
|
||||
(cd capture_sdr_rtladsb && $(MAKE) install) \
|
||||
fi;
|
||||
|
||||
@if test "$(BUILD_CAPTURE_FREAKLABS_ZIGBEE)"x = "1"x; then \
|
||||
(cd capture_freaklabs_zigbee && $(MAKE) install) \
|
||||
fi;
|
||||
|
||||
mkdir -p $(LIB)/pkgconfig
|
||||
$(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 644 packaging/kismet.pc $(LIB)/pkgconfig/kismet.pc
|
||||
|
||||
mkdir -p $(HTTPD)
|
||||
cp -r http_data/* $(HTTPD)
|
||||
|
||||
cp conf/kismet_manuf.txt $(SHARE)/kismet_manuf.txt
|
||||
|
||||
|
||||
CONFINSTTARGETS = $(addprefix install_conf_, $(CONFIGFILES))
|
||||
${CONFINSTTARGETS}: install_conf_%:
|
||||
@if test -f $(ETC)/$*; then \
|
||||
echo "$(ETC)/$* already exists; it will not be automatically replaced."; \
|
||||
else \
|
||||
echo install -o $(INSTUSR) -g $(INSTGRP) -m 644 conf/$* $(ETC)/$*; \
|
||||
$(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 644 conf/$* $(ETC)/$*; \
|
||||
fi
|
||||
|
||||
FORCECONFINSTTARGETS = $(addprefix install_force_conf_, $(CONFIGFILES))
|
||||
${FORCECONFINSTTARGETS}: install_force_conf_%:
|
||||
$(INSTALL) -o $(INSTUSR) -g $(INSTGRP) -m 644 conf/$* $(ETC)/$*;
|
||||
|
||||
configsinstall:
|
||||
$(MAKE) $(CONFINSTTARGETS)
|
||||
|
||||
@echo
|
||||
@echo
|
||||
@echo "Existing config files have not been replaced; if the Kismet ";
|
||||
@echo "configuration files have changed, you will need to manually ";
|
||||
@echo "reconcile the differences in the config files!";
|
||||
@echo "You can replace all config files with: ";
|
||||
@echo " make forceconfigs";
|
||||
@echo
|
||||
@echo "You can simplify future configuration changes by using the ";
|
||||
@echo "kismet_site.conf config file, for more info see the docs at:";
|
||||
@echo "https://www.kismetwireless.net/docs/readme/config_files/";
|
||||
@echo
|
||||
@echo
|
||||
|
||||
suidinstall: $(PS) $(DATASOURCE_BINS)
|
||||
-groupadd -r -f $(SUIDGROUP)
|
||||
|
||||
@$(MAKE) -e commoninstall
|
||||
@$(MAKE) -e binsuidinstall
|
||||
|
||||
@$(MAKE) configsinstall
|
||||
|
||||
@echo
|
||||
@echo
|
||||
@echo "Installed kismet into $(BIN)/."
|
||||
@echo "If you have not done so already, read the README file and the FAQ file. Additional"
|
||||
@echo "documentation is in the docs/ directory. You MUST edit $(ETC)/kismet.conf "
|
||||
@echo "and configure Kismet for your system, or it will NOT run properly!"
|
||||
@echo
|
||||
@echo "Kismet has been installed with a SUID ROOT CAPTURE HELPER executeable by "
|
||||
@echo "users in the group '" $(SUIDGROUP) "'. This WILL ALLOW USERS IN THIS GROUP "
|
||||
@echo "TO ALTER YOUR NETWORK INTERACE STATES, but is more secure than running "
|
||||
@echo "all of Kismet as root. ONLY users in this group will be able to "
|
||||
@echo "run Kismet and capture from physical network devices."
|
||||
@echo
|
||||
@echo "If you have just created this group, you will need to log out and back in"
|
||||
@echo "before your user will have access. Check the output of the 'groups' "
|
||||
@echo "command to make sure your user has the proper group!"
|
||||
@echo
|
||||
@echo "If you have installed Kismet in the past, you may need to UPDATE YOUR CONFIG"
|
||||
@echo "FILES or Kismet may not work properly! You can manually reconcile differences"
|
||||
@echo "or you can replace the previously installed config files entirely by running"
|
||||
@echo "make forceconfigs"
|
||||
|
||||
install: $(INSTBINS)
|
||||
@$(MAKE) -e commoninstall
|
||||
|
||||
@$(MAKE) configsinstall
|
||||
|
||||
@echo
|
||||
@echo
|
||||
@echo "Installed kismet into $(BIN)/."
|
||||
@echo "If you have not done so already, read the README file and the FAQ file. Additional"
|
||||
@echo "documentation is in the docs/ directory. You MUST edit $(ETC)/kismet.conf "
|
||||
@echo "and configure Kismet for your system, or it will NOT run properly!"
|
||||
@echo
|
||||
@echo "Kismet has NOT been installed suid-root. This means you will need to start "
|
||||
@echo "it as root. If you add your user to the $(SUIDGROUP) group and install "
|
||||
@echo "Kismet with 'make suidinstall', users in that group will be able to "
|
||||
@echo "run Kismet directly."
|
||||
@echo
|
||||
@echo "READ THE KISMET DOCUMENTATION ABOUT THE KISMET SECURITY MODEL TO"
|
||||
@echo "DECIDE IF YOU WANT TO INSTALL IT SUID-ROOT"
|
||||
@echo
|
||||
@echo "It is generally *MORE SECURE* to install Kismet with the suid-root "
|
||||
@echo "option."
|
||||
@echo
|
||||
@echo "If you have installed Kismet in the past, you may need to UPDATE YOUR CONFIG"
|
||||
@echo "FILES or Kismet may not work properly! You can manually reconcile differences"
|
||||
@echo "or you can replace the previously installed config files entirely by running"
|
||||
@echo "make forceconfigs"
|
||||
|
||||
forceconfigs:
|
||||
$(MAKE) $(FORCECONFINSTTARGETS)
|
||||
|
||||
uavconfig:
|
||||
@echo "Generating kismet_uav.conf"
|
||||
@python tools/compile_uav_conf.py conf/kismet_uav.conf.yaml > conf/kismet_uav.conf
|
||||
|
||||
manuf:
|
||||
@echo "Generating kismet_manuf.txt"
|
||||
@python tools/create_oui_db.py > conf/kismet_manuf.txt
|
||||
|
||||
rpm:
|
||||
@echo "Disabling SUID installation (RPM will handle setting the SUID bit.)"
|
||||
@( export SUID="no"; export INSTGRP=`id -g`; export MANGRP=`id -g`; \
|
||||
export INSTUSR=`id -u`; $(MAKE) -e install )
|
||||
|
||||
depclean:
|
||||
@-rm -f *.d
|
||||
@-rm -f log_tools/*.d
|
||||
|
||||
clean:
|
||||
@-rm -f *.o *.mo
|
||||
@-rm -f *.d
|
||||
# @-rm -f kaitai_parsers/*.o
|
||||
# @-rm -f kaitai_parsers/*.d
|
||||
@-rm -f dot11_parsers/*.o
|
||||
@-rm -f dot11_parsers/*.d
|
||||
@-rm -f bluetooth_parsers/*.o
|
||||
@-rm -f bluetooth_parsers/*.d
|
||||
@-rm -f protobuf_cpp/*.pb.*
|
||||
@-rm -f protobuf_c/*.pb-c.*
|
||||
@-rm -f log_tools/*.o
|
||||
@-rm -f log_tools/*.d
|
||||
@-$(MAKE) all-plugins-clean
|
||||
@-rm -f $(PS)
|
||||
@-rm -f $(BUILD_CAPTURE_PCAPFILE)
|
||||
@-rm -f $(BUILD_CAPTURE_KISMETDB)
|
||||
@-rm -f $(BUILD_CAPTURE_LINUX_WIFI)
|
||||
@-rm -f $(BUILD_CAPTURE_LINUX_BLUETOOTH)
|
||||
@-rm -f $(BUILD_CAPTURE_OSX_COREWLAN)
|
||||
@-rm -f $(BUILD_CAPTURE_HACKRF_SWEEP)
|
||||
@-rm -f $(DATASOURCE_COMMON_A)
|
||||
@(cd capture_linux_bluetooth && make clean)
|
||||
@(cd capture_linux_wifi && make clean)
|
||||
@(cd capture_osx_corewlan_wifi && make clean)
|
||||
@(cd capture_sdr_rtl433 && make clean)
|
||||
@(cd capture_sdr_rtlamr && make clean)
|
||||
@(cd capture_sdr_rtladsb && make clean)
|
||||
|
||||
distclean:
|
||||
@-$(MAKE) clean
|
||||
@-$(MAKE) all-plugins-clean
|
||||
@-rm -f *~
|
||||
@-rm -f config.status
|
||||
@-rm -f config.h
|
||||
@-rm -f config.log
|
||||
@-rm -rf packaging/ipkg/usr
|
||||
@-rm -rf packaging/pak
|
||||
@-rm -rf *.ipk
|
||||
@-rm -f scripts/kismet
|
||||
@-rm -f Makefile
|
||||
|
||||
plugins: Makefile
|
||||
@( export KIS_SRC_DIR=`pwd`; for x in plugin-*/; do if [ ! -d "$$x" ]; then continue; fi; echo "PLUGIN: $$x"; ( cd "$$x"; make; ); done )
|
||||
|
||||
restricted-plugins: Makefile
|
||||
@( export KIS_SRC_DIR=`pwd`; for x in restricted-plugin-*/; do if [ ! -d "$$x" ]; then continue; fi; echo "PLUGIN: $$x"; ( cd "$$x"; make; ); done )
|
||||
|
||||
plugins-clean:
|
||||
@( export KIS_SRC_DIR=`pwd`; for x in plugin-*/; do if [ ! -d "$$x" ]; then continue; fi; echo "PLUGIN-CLEAN: $$x"; ( cd "$$x"; make clean; ); done )
|
||||
|
||||
restricted-plugins-clean:
|
||||
@( export KIS_SRC_DIR=`pwd`; for x in restricted-plugin-*/; do if [ ! -d "$$x" ]; then continue; fi; echo "PLUGIN-CLEAN: $$x"; ( cd "$$x"; make clean; ); done )
|
||||
|
||||
plugins-install: Makefile
|
||||
@( export KIS_SRC_DIR=`pwd`; for x in plugin-*/; do if [ ! -d "$$x" ]; then continue; fi; echo "PLUGIN-INSTALL: $$x"; ( cd "$$x"; make install; ); done )
|
||||
|
||||
restricted-plugins-install: Makefile
|
||||
@( export KIS_SRC_DIR=`pwd`; for x in restricted-plugin-*/; do if [ ! -d "$$x" ]; then continue; fi; echo "PLUGIN-INSTALL: $$x"; ( cd "$$x"; make install; ); done )
|
||||
|
||||
plugins-userinstall: Makefile
|
||||
@( export KIS_SRC_DIR=`pwd`; for x in plugin-*/; do if [ ! -d "$$x" ]; then continue; fi; echo "PLUGIN-USERINSTALL: $$x"; ( cd "$$x"; make userinstall; ); done )
|
||||
|
||||
restricted-plugins-userinstall: Makefile
|
||||
@( export KIS_SRC_DIR=`pwd`; for x in restricted-plugin-*/; do if [ ! -d "$$x" ]; then continue; fi; echo "PLUGIN-USERINSTALL: $$x"; ( cd "$$x"; make userinstall; ); done )
|
||||
|
||||
all-plugins: Makefile
|
||||
@$(MAKE) plugins
|
||||
@$(MAKE) restricted-plugins
|
||||
|
||||
all-plugins-install: Makefile
|
||||
@$(MAKE) plugins-install
|
||||
@$(MAKE) restricted-plugins-install
|
||||
|
||||
all-plugins-userinstall: Makefile
|
||||
@$(MAKE) plugins-userinstall
|
||||
@$(MAKE) restricted-plugins-userinstall
|
||||
|
||||
all-plugins-clean: Makefile
|
||||
@$(MAKE) plugins-clean
|
||||
@$(MAKE) restricted-plugins-clean
|
||||
|
||||
# Disabled
|
||||
# kaitai-parsers:
|
||||
# @echo "Re-generating the kaitai_struct parsers requires the gpl3 licensed "
|
||||
# @echo "kaitai_struct compiler; see http://http://kaitai.io/ for more info!"
|
||||
# kaitai-struct-compiler --outdir kaitai_parsers/ -t cpp_stl -I kaitai_definitions/ kaitai_definitions/*.ksy
|
||||
# file-rename -v -f 's/\.cpp$$/\.cc/' kaitai_parsers/*.cpp
|
||||
|
||||
protobuf_cpp/%.pb.cc.d: %.pb.cc
|
||||
protobuf_cpp/%.pb.cc.o: %.pb.cc
|
||||
protobuf_cpp/%.pb.cc: protobuf_definitions/%.proto
|
||||
$(PROTOCBIN) --cpp_out=./protobuf_cpp/ -I protobuf_definitions/ protobuf_definitions/$*.proto
|
||||
protobuf_cpp/%.pb.h: protobuf_definitions/%.proto
|
||||
$(PROTOCBIN) --cpp_out=./protobuf_cpp/ -I protobuf_definitions/ protobuf_definitions/$*.proto
|
||||
|
||||
protobuf_c/%.pb-c.c.o: %.pb-c.c
|
||||
protobuf_c/%.pb-c.c: protobuf_definitions/%.proto
|
||||
$(PROTOCCBIN) --c_out=./protobuf_c/ -I protobuf_definitions/ protobuf_definitions/$*.proto
|
||||
protobuf_c/%.pb-c.h: protobuf_definitions/%.proto
|
||||
$(PROTOCCBIN) --c_out=./protobuf_c/ -I protobuf_definitions/ protobuf_definitions/$*.proto
|
||||
|
||||
%.c.o: %.c
|
||||
%.c.o : %.c %.c.d
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c $*.c -o $@
|
||||
|
||||
%.cc.o: %.cc
|
||||
%.cc.o: %.cc %.cc.d
|
||||
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $*.cc -o $@
|
||||
|
||||
%.c.d: %.c $(PROTOBUF_C_H)
|
||||
$(CC) -MM $(CFLAGS) $(CPPFLAGS) -MT $*.c.o $*.c > $*.c.d
|
||||
|
||||
%.cc.d: %.cc $(PROTOBUF_CPP_H_TARGET)
|
||||
$(CXX) -MM $(CXXFLAGS) $(CPPFLAGS) -MT $*.cc.o $*.cc > $*.cc.d
|
||||
|
||||
.PRECIOUS: %.c %.cc %.h %.Td %.c.d %.cc.d protobuf_cpp/%.pb.cc protobuf_cpp/%.pb.h protobuf_c/%.pb-c.c protouf_c/%.pb-c.h
|
||||
|
||||
include $(wildcard $(patsubst %cc.o,%cc.d,$(PSO)))
|
||||
include $(wildcard $(patsubst %c.o,%c.d,$(PSO)))
|
||||
include $(wildcard $(patsubst %c.o,%c.d,$(DATASOURCE_COMMON_C_O)))
|
||||
ifneq ($(BUILD_CAPTURE_PCAPFILE)x, "x")
|
||||
include $(wildcard $(patsubst %c.o,%c.d,$(CAPTURE_PCAPFILE_O)))
|
||||
endif
|
||||
ifneq ($(BUILD_CAPTURE_KISMETDB)x, "x")
|
||||
include $(wildcard $(patsubst %c.o,%c.d,$(CAPTURE_KISMETDB_O)))
|
||||
endif
|
||||
include $(wildcard $(patsubst %cc.o,%cc.d,$(LOGTOOL_KISMETDB_WIGLE_O)))
|
||||
include $(wildcard $(patsubst %cc.o,%cc.d,$(LOGTOOL_KISMETDB_STRIP_O)))
|
||||
include $(wildcard $(patsubst %cc.o,%cc.d,$(LOGTOOL_KISMETDB_JSON_O)))
|
||||
include $(wildcard $(patsubst %cc.o,%cc.d,$(LOGTOOL_KISMETDB_STATS_O)))
|
||||
|
||||
.SUFFIXES: .c .cc .o
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
INSTGRP ?= "@instgrp@"
|
||||
MANGRP ?= "@mangrp@"
|
||||
INSTUSR ?= "root"
|
||||
|
||||
BLDHOME = @srcdir@
|
||||
|
||||
CXX = @CXX@
|
||||
CC = @CC@
|
||||
LD = @CXX@
|
||||
CCLD = @CC@
|
||||
|
||||
LDFLAGS += @LDFLAGS@
|
||||
CFLAGS += -Wall -g -I. @NMCFLAGS@ @NLCFLAGS@ @CPPFLAGS@ @PTHREAD_CFLAGS@ @PROTOCCFLAGS@
|
||||
CXXFLAGS += -Wall -g -I. @CXXFLAGS@ @PROTOCFLAGS@ -DKS_STR_ENCODING_NONE
|
||||
CPPFLAGS += @CPPFLAGS@
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
|
||||
LIBS += @LIBS@
|
||||
KSLIBS += @KSLIBS@ @PTHREAD_LIBS@ @PROTOLIBS@
|
||||
|
||||
PTHREADLIBS = @PTHREAD_LIBS@
|
||||
CAPLIBS = @caplibs@
|
||||
NETLINKLIBS = @NLLIBS@
|
||||
AIRCAPLIBS = @airpcaplib@
|
||||
|
||||
PROTOLIBS = @PROTOLIBS@
|
||||
PROTOCFLAGS = @PROTOCFLAGS@
|
||||
PROTOCBIN ?= @PROTOCBIN@
|
||||
|
||||
PROTOCLIBS = @PROTOCLIBS@
|
||||
PROCOCCFLAGS = @PROTOCCFLAGS@
|
||||
PROTOCCBIN ?= @PROTOCCBIN@
|
||||
|
||||
PTHREADCFLAGS = @PTHREAD_CFLAGS@
|
||||
NMFLAGS = @NMCFLAGS@
|
||||
NMLIBS = @NMLIBS@
|
||||
|
||||
PCAPLIBS = @pcaplnk@
|
||||
|
||||
LIBMLIB = @LIBMLIB@
|
||||
|
||||
SUIDGROUP = @suidgroup@
|
||||
|
||||
DATASOURCE_LIBS += $(CAPLIBS) @PTHREAD_LIBS@ @PROTOCLIBS@ -lm
|
||||
|
||||
PYTHON2 ?= @PYTHON2@
|
||||
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
plugindir = @libdir@/kismet
|
||||
ETC = ${DESTDIR}@sysconfdir@
|
||||
BIN = ${DESTDIR}@bindir@
|
||||
SHARE = ${DESTDIR}@datadir@/kismet/
|
||||
MAN = ${DESTDIR}@mandir@
|
||||
LIB = ${DESTDIR}@libdir@
|
||||
WAV = ${DESTDIR}@datadir@/kismet/wav/
|
||||
HTTPD = ${DESTDIR}@datadir@/kismet/httpd/
|
||||
|
||||
PLUGINLDFLAGS += @PLUGINLDFLAGS@ @LDFLAGS@
|
||||
|
||||
GIT ?= git
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,183 +0,0 @@
|
|||
Kismet Webserver and SSL
|
||||
|
||||
xx. When should I use SSL?
|
||||
|
||||
SSL provides encryption between the Kismet server and a web browser
|
||||
communicating with it.
|
||||
|
||||
SSL is not generally necessary when using Kismet locally (like your
|
||||
laptop or a dedicated device), however if you plan to use Kismet remotely
|
||||
over a public network, you should strongly consider enabling SSL.
|
||||
|
||||
Without SSL enabled, your data (and your Kismet Web UI login and password)
|
||||
will be sent in plaintext, which is likely not something you want.
|
||||
|
||||
xx. Enabling SSL
|
||||
|
||||
SSL is enabled in the kismet_httpd.conf configuration file by setting
|
||||
|
||||
httpd_ssl=true
|
||||
|
||||
and providing a PEM-formatted SSL certificate and key via:
|
||||
|
||||
httpd_ssl_cert=/path/to/cert
|
||||
and
|
||||
httpd_ssl_key=/path/to/key
|
||||
|
||||
xx. Getting a certificate
|
||||
|
||||
Kismet can use either a legitimate (signed by a trusted authority)
|
||||
certificate, or you can provide a self-signed cert.
|
||||
|
||||
If using a real certificate, follow the instructions from your certificate
|
||||
provider for creating a key and certificate request, and submit it for
|
||||
signing.
|
||||
|
||||
If you wish to use a self-signed certificate, follow the instructions
|
||||
below.
|
||||
|
||||
WARNING: Self-signed certificates provide the same encryption, but DO NOT
|
||||
certify that a host is legitimate. Because a self-signed certificate is
|
||||
not automatically trusted by your browser, you WILL receive a SSL error
|
||||
when you visit the Kismet Web UI. You MUST confirm that the certificate
|
||||
you are seeing is the certificate you expect. If you do not verify
|
||||
the certificate yourself, you may be susceptible to man-in-the-middle
|
||||
interception.
|
||||
|
||||
WARNING: ANY THIRD PARTY CLIENT which communicates with a SSL-enabled
|
||||
Kismet server MUST PROVIDE A METHOD FOR THE USER TO VALIDATE AND PIN THE
|
||||
CERTIFICATE. Accepting all SSL certificates is NOT valid.
|
||||
|
||||
xx. Using LetsEncrypt certificates
|
||||
|
||||
LetsEncrypt (https://letsencrypt.org) provides free, signed SSL
|
||||
certificates which are accepted by most browsers. These certificates
|
||||
can be used with Kismet and may offer a simpler and more secure option
|
||||
than self-signed certificates.
|
||||
|
||||
LetsEncrypt currently uses a set of python (or third-party) clients
|
||||
to automatically generate certificates. In order to verify that you
|
||||
control the domain the certificate is issued for, you must run these
|
||||
scripts on the webserver with that domain.
|
||||
|
||||
Once the certificates are generated, they must be provided to Kismet.
|
||||
You must provide the key file and the full chain certificate (by
|
||||
default named "full-chain.cer"). These files are already in PEM format.
|
||||
|
||||
To use a letsencrypt certificate without errors, Kismet must be running
|
||||
on the server with that public domain name, or the connection to Kismet
|
||||
must be forwarded, such as port forwarding over SSH. (See the
|
||||
'SSH Forwarding' section for an example)
|
||||
|
||||
xx. Generating a self-signed certificate
|
||||
|
||||
When using a self-signed certificate, keep in mind the warnings above in
|
||||
"Getting a certificate".
|
||||
|
||||
To generate a self-signed certificate on Linux using the OpenSSL command
|
||||
line tools:
|
||||
|
||||
1. Generate a RSA key. This is the private key used to encrypt your
|
||||
certificate. You will need to generate a keyfile without an embedded
|
||||
password.
|
||||
|
||||
$ openssl genrsa -out kismet.key 4096
|
||||
|
||||
This will generate a 4096-bit RSA keyfile.
|
||||
|
||||
2. Generate a CSR (certificate request). This is the request which
|
||||
defines the public data in your certificate, and links it to the
|
||||
key file.
|
||||
|
||||
$ openssl req -new -key kismet.key -out kismet.csr
|
||||
|
||||
You will be prompted to enter information to put in the certificate
|
||||
(Country name, State, etc). If you were generating a legitimate
|
||||
certificate, this information would matter, but on a self-signed cert,
|
||||
it is less relevant. Enter information which is recognizable and
|
||||
makes sense to you.
|
||||
|
||||
On the Common Name field, enter the public name of your server.
|
||||
|
||||
When prompted to enter a challenge password, leave it blank.
|
||||
|
||||
3. Create the self-signed certificate:
|
||||
|
||||
$ openssl x509 -req -days 365 -in kismet.csr \
|
||||
-signkey kismet.key -out kismet.pem
|
||||
|
||||
This will generate a request for a certificate which is valid from the
|
||||
time you run the command until a year in the future. To make a
|
||||
certificate valid for longer than a year, change the -days parameter.
|
||||
|
||||
4. Verify your certificate is what you expected
|
||||
|
||||
$ openssl x509 -in kismet.pem -noout -text
|
||||
|
||||
This should print out information about your certificate, including
|
||||
the signature you will need to validate it in the future.
|
||||
|
||||
Once you have generated your certificate, copy it and configure Kismet
|
||||
to use SSL and point at your certificate. For example, if you
|
||||
copied your .pem and .key files into ~/.kismet/ssl/, you would configure
|
||||
Kismet:
|
||||
|
||||
httpd_ssl=true
|
||||
httpd_ssl_cert=%h/.kismet/ssl/kismet.pem
|
||||
httpd_ssl_key=%h/.kismet/ssl/kismet.key
|
||||
|
||||
xx. Converting certificates
|
||||
|
||||
Kismet requires that the certificate be in PEM format. If you are using
|
||||
a certificate signed by a certificate authority, you may receive the
|
||||
certificate in DER format.
|
||||
|
||||
If you are unsure what format a certificate file is in, open it in a
|
||||
standard editor or use the 'cat' command. A PEM format certificate
|
||||
will include '-----BEGIN CERTIFICATE----', while a DER format certificate
|
||||
will be pure binary.
|
||||
|
||||
To convert a DER to PEM certificate:
|
||||
|
||||
$ openssl x509 -inform der -in certificate.cer -out certificate.pem
|
||||
|
||||
xx. Intermediary certificates
|
||||
|
||||
Many certificate authorities use an intermediary signing certificate.
|
||||
|
||||
This certificate must be included in the chain presented by the server
|
||||
to be valid in all browsers (Typically, Chrome works without intermediary
|
||||
certificates, but command-line tools like 'curl' and other OpenSSL based
|
||||
code, such as embedded https clients in Python, Ruby, etc, does not.
|
||||
|
||||
If you are using an official certificate, and need to include the
|
||||
intermediary certificate from your provider, simply concatenate it with
|
||||
your server certificate:
|
||||
|
||||
$ cat kismet.pem intermediate.pem > combo.pem
|
||||
|
||||
And use the combined certificate in your kismet_httpd.conf:
|
||||
|
||||
httpd_ssl_cert=%h/.kismet/ssl/combo.pem
|
||||
|
||||
The order of certificate files is important: Your server certificate
|
||||
must come before the intermediary certificate.
|
||||
|
||||
xx. SSH forwarding
|
||||
|
||||
To take advantage of a SSL certificate which has a valid domain name
|
||||
and is signed by an accepted authority, Kismet must be accessible via
|
||||
the dns name the certificate is generated for.
|
||||
|
||||
Often a preferable option to running Kismet on the server itself is to
|
||||
set up port forwarding via SSH.
|
||||
|
||||
To enable public port forwarding, first the GatewayPorts option must
|
||||
be enabled on the server in sshd_config:
|
||||
|
||||
GatewayPorts yes
|
||||
|
||||
Then a SSH session with remote port forwarding should be established:
|
||||
|
||||
$ ssh -R *:2501:localhost:2501 user@host
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
https://www.kismetwireless.net
|
||||
|
||||
To facilitate building the website docs, the README is now broken up into multiple files, which can be found in the `docs/readme/` directory.
|
||||
|
||||
The generated Kismet docs can be most easily found and read at [the Kismet website](https://www.kismetwireless.net/docs/readme/quickstart/)
|
||||
|
||||
|
||||
|
||||
|
||||
Docs are now generated from a Git sub-repository at:
|
||||
|
||||
```bash
|
||||
$ git clone https://www.kismetwireless.net/git/kismet-docs.git
|
||||
```
|
||||
|
||||
and mirrored on Github at:
|
||||
|
||||
```bash
|
||||
$ git clone https://www.github.com/kismetwireless/kismet-docs
|
||||
```
|
||||
|
|
@ -1 +0,0 @@
|
|||
2019-04-GIT
|
|
@ -1,853 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
|
||||
#include "alertracker.h"
|
||||
#include "devicetracker.h"
|
||||
#include "configfile.h"
|
||||
|
||||
#include "json_adapter.h"
|
||||
#include "structured.h"
|
||||
#include "kismet_json.h"
|
||||
#include "base64.h"
|
||||
#include "kis_databaselogfile.h"
|
||||
|
||||
Alertracker::Alertracker() :
|
||||
Kis_Net_Httpd_CPPStream_Handler() {
|
||||
|
||||
next_alert_id = 0;
|
||||
|
||||
packetchain = Globalreg::FetchMandatoryGlobalAs<Packetchain>();
|
||||
entrytracker = Globalreg::FetchMandatoryGlobalAs<EntryTracker>();
|
||||
|
||||
alert_vec_id =
|
||||
entrytracker->RegisterField("kismet.alert.list",
|
||||
TrackerElementFactory<TrackerElementVector>(),
|
||||
"list of alerts");
|
||||
|
||||
alert_timestamp_id =
|
||||
entrytracker->RegisterField("kismet.alert.timestamp",
|
||||
TrackerElementFactory<TrackerElementDouble>(),
|
||||
"alert update timestamp");
|
||||
|
||||
alert_entry_id =
|
||||
entrytracker->RegisterField("kismet.alert.alert",
|
||||
TrackerElementFactory<tracked_alert>(),
|
||||
"Kismet alert");
|
||||
|
||||
|
||||
alert_defs_vec =
|
||||
entrytracker->RegisterAndGetFieldAs<TrackerElementVector>("kismet.alert.definition_list",
|
||||
TrackerElementFactory<TrackerElementVector>(),
|
||||
"Kismet alert definitions");
|
||||
|
||||
alert_def_id =
|
||||
entrytracker->RegisterField("kismet.alert.alert_definition",
|
||||
TrackerElementFactory<tracked_alert_definition>(),
|
||||
"Kismet alert definition");
|
||||
|
||||
// Register the alert component
|
||||
pack_comp_alert =
|
||||
packetchain->RegisterPacketComponent("alert");
|
||||
|
||||
// Register a KISMET alert type with no rate restrictions
|
||||
alert_ref_kismet =
|
||||
RegisterAlert("KISMET", "Server events", sat_day, 0, sat_day, 0, KIS_PHY_ANY);
|
||||
|
||||
|
||||
Bind_Httpd_Server();
|
||||
|
||||
if (Globalreg::globalreg->kismet_config == NULL) {
|
||||
fprintf(stderr, "FATAL OOPS: Alertracker called with null config\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef PRELUDE
|
||||
// Start client Prelude
|
||||
int ret;
|
||||
ret = prelude_init(0, NULL);
|
||||
if (ret < 0) {
|
||||
_MSG("Alertracker - Failed to initialize Prelude SIEM connection", MSGFLAG_FATAL);
|
||||
globalreg->fatal_condition = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
PreludeInitClient(PRELUDE_ANALYZER_MODEL);
|
||||
#endif
|
||||
|
||||
if (Globalreg::globalreg->kismet_config->FetchOpt("alertbacklog") != "") {
|
||||
int scantmp;
|
||||
if (sscanf(Globalreg::globalreg->kismet_config->FetchOpt("alertbacklog").c_str(),
|
||||
"%d", &scantmp) != 1 || scantmp < 0) {
|
||||
_MSG("Illegal value for 'alertbacklog' in kismet.conf, expected number greater than zero.",
|
||||
MSGFLAG_FATAL);
|
||||
Globalreg::globalreg->fatal_condition = 1;
|
||||
return;
|
||||
}
|
||||
num_backlog = scantmp;
|
||||
}
|
||||
|
||||
// Parse config file vector of all alerts
|
||||
if (ParseAlertConfig(Globalreg::globalreg->kismet_config) < 0) {
|
||||
_MSG("Failed to parse alert values from Kismet config file", MSGFLAG_FATAL);
|
||||
Globalreg::globalreg->fatal_condition = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
log_alerts = Globalreg::globalreg->kismet_config->FetchOptBoolean("kis_log_alerts", true);
|
||||
}
|
||||
|
||||
Alertracker::~Alertracker() {
|
||||
local_locker lock(&alert_mutex);
|
||||
|
||||
Globalreg::globalreg->RemoveGlobal("ALERTTRACKER");
|
||||
Globalreg::globalreg->alertracker = NULL;
|
||||
|
||||
#ifdef PRELUDE
|
||||
prelude_deinit();
|
||||
delete prelude_client;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Alertracker::PreludeInitClient(const char *analyzer_name) {
|
||||
#ifdef PRELUDE
|
||||
try {
|
||||
string version =
|
||||
globalreg->version_major + "." +
|
||||
globalreg->version_minor + "." +
|
||||
globalreg->version_tiny;
|
||||
|
||||
prelude_client =
|
||||
new Prelude::ClientEasy(analyzer_name, 4, PRELUDE_ANALYZER_MODEL,
|
||||
PRELUDE_ANALYZER_CLASS, PRELUDE_ANALYZER_MANUFACTURER, version.c_str());
|
||||
prelude_client->start();
|
||||
} catch (Prelude::PreludeError const & error) {
|
||||
_MSG(std::string("Alertracker failed to initialize connection to Prelude: ") +
|
||||
error.what(), MSGFLAG_FATAL);
|
||||
globalreg->fatal_condition = 1;
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int Alertracker::RegisterAlert(std::string in_header, std::string in_description,
|
||||
alert_time_unit in_unit, int in_rate, alert_time_unit in_burstunit,
|
||||
int in_burst, int in_phy) {
|
||||
local_locker lock(&alert_mutex);
|
||||
|
||||
// Bail if this header is registered
|
||||
if (alert_name_map.find(in_header) != alert_name_map.end()) {
|
||||
_MSG("Tried to re-register duplicate alert " + in_header, MSGFLAG_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Make sure we're not going to overstep our range
|
||||
if ((unsigned int) in_burstunit > sat_day)
|
||||
in_burstunit = sat_day;
|
||||
if ((unsigned int) in_unit > sat_day)
|
||||
in_unit = sat_day;
|
||||
|
||||
// Bail if the rates are impossible
|
||||
if (in_burstunit > in_unit) {
|
||||
_MSG("Failed to register alert " + in_header + ", time unit for "
|
||||
"burst rate must be less than or equal to the time unit "
|
||||
"for the max rate", MSGFLAG_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto arec =
|
||||
std::make_shared<tracked_alert_definition>(alert_def_id);
|
||||
|
||||
arec->set_alert_ref(next_alert_id++);
|
||||
arec->set_header(StrUpper(in_header));
|
||||
arec->set_description(in_description);
|
||||
arec->set_limit_unit(in_unit);
|
||||
arec->set_limit_rate(in_rate);
|
||||
arec->set_burst_unit(in_burstunit);
|
||||
arec->set_limit_burst(in_burst);
|
||||
arec->set_phy(in_phy);
|
||||
arec->set_time_last(0);
|
||||
|
||||
alert_name_map.insert(std::make_pair(arec->get_header(), arec->get_alert_ref()));
|
||||
alert_ref_map.insert(std::make_pair(arec->get_alert_ref(), arec));
|
||||
|
||||
alert_defs_vec->push_back(arec);
|
||||
|
||||
return arec->get_alert_ref();
|
||||
}
|
||||
|
||||
int Alertracker::FetchAlertRef(std::string in_header) {
|
||||
local_locker lock(&alert_mutex);
|
||||
|
||||
auto ni = alert_name_map.find(in_header);
|
||||
|
||||
if (ni != alert_name_map.end())
|
||||
return ni->second;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Alertracker::CheckTimes(shared_alert_def arec) {
|
||||
// Alerts limited to 0 are squelched
|
||||
if (arec->get_limit_rate() == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
// If the last time we sent anything was longer than the main rate limit,
|
||||
// then we reset back to empty
|
||||
if (arec->get_time_last() < (now.tv_sec -
|
||||
alert_time_unit_conv[arec->get_limit_unit()])) {
|
||||
arec->set_total_sent(0);
|
||||
arec->set_burst_sent(0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// If the last time we sent anything was longer than the burst rate, we can
|
||||
// reset the burst to 0
|
||||
if (arec->get_time_last() < (now.tv_sec -
|
||||
alert_time_unit_conv[arec->get_burst_unit()])) {
|
||||
arec->set_burst_sent(0);
|
||||
}
|
||||
|
||||
// If we're under the limit on both, we're good to go
|
||||
if (arec->get_burst_sent() < arec->get_limit_burst() &&
|
||||
arec->get_total_sent() < arec->get_limit_rate())
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Alertracker::PotentialAlert(int in_ref) {
|
||||
local_locker lock(&alert_mutex);
|
||||
|
||||
std::map<int, shared_alert_def>::iterator aritr = alert_ref_map.find(in_ref);
|
||||
|
||||
if (aritr == alert_ref_map.end())
|
||||
return 0;
|
||||
|
||||
shared_alert_def arec = aritr->second;
|
||||
|
||||
return CheckTimes(arec);
|
||||
}
|
||||
|
||||
int Alertracker::RaiseAlert(int in_ref, kis_packet *in_pack,
|
||||
mac_addr bssid, mac_addr source, mac_addr dest,
|
||||
mac_addr other, std::string in_channel, std::string in_text) {
|
||||
|
||||
local_demand_locker lock(&alert_mutex);
|
||||
|
||||
lock.lock();
|
||||
|
||||
std::map<int, shared_alert_def>::iterator aritr = alert_ref_map.find(in_ref);
|
||||
|
||||
if (aritr == alert_ref_map.end())
|
||||
return -1;
|
||||
|
||||
shared_alert_def arec = aritr->second;
|
||||
|
||||
if (CheckTimes(arec) != 1)
|
||||
return 0;
|
||||
|
||||
lock.unlock();
|
||||
|
||||
kis_alert_info *info = new kis_alert_info;
|
||||
|
||||
info->header = arec->get_header();
|
||||
info->phy = arec->get_phy();
|
||||
gettimeofday(&(info->tm), NULL);
|
||||
|
||||
info->bssid = bssid;
|
||||
info->source = source;
|
||||
info->dest = dest;
|
||||
info->other = other;
|
||||
|
||||
info->channel = in_channel;
|
||||
|
||||
info->text = in_text;
|
||||
|
||||
// Increment and set the timers
|
||||
arec->inc_burst_sent(1);
|
||||
arec->inc_total_sent(1);
|
||||
arec->set_time_last(ts_to_double(info->tm));
|
||||
|
||||
lock.lock();
|
||||
|
||||
alert_backlog.push_back(info);
|
||||
if ((int) alert_backlog.size() > num_backlog) {
|
||||
delete alert_backlog[0];
|
||||
alert_backlog.erase(alert_backlog.begin());
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
|
||||
// Try to get the existing alert info
|
||||
if (in_pack != NULL) {
|
||||
auto acomp = in_pack->fetch<kis_alert_component>(pack_comp_alert);
|
||||
|
||||
// if we don't have an alert container, make one on this packet
|
||||
if (acomp == NULL) {
|
||||
acomp = new kis_alert_component;
|
||||
in_pack->insert(pack_comp_alert, acomp);
|
||||
}
|
||||
|
||||
// Attach it to the packet
|
||||
acomp->alert_vec.push_back(info);
|
||||
}
|
||||
|
||||
#ifdef PRELUDE
|
||||
// Send alert to Prelude
|
||||
RaisePreludeAlert(in_ref, in_pack, info->bssid, info->source,
|
||||
info->dest, info->other, info->channel, info->text);
|
||||
#endif
|
||||
|
||||
// Send the text info
|
||||
_MSG(info->header + " " + info->text, MSGFLAG_ALERT);
|
||||
|
||||
if (log_alerts) {
|
||||
auto dbf =
|
||||
Globalreg::FetchGlobalAs<KisDatabaseLogfile>("DATABASELOG");
|
||||
if (dbf != NULL) {
|
||||
auto ta = std::make_shared<tracked_alert>(alert_entry_id);
|
||||
ta->from_alert_info(info);
|
||||
dbf->log_alert(ta);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Alertracker::RaiseOneShot(std::string in_header, std::string in_text, int in_phy) {
|
||||
local_demand_locker lock(&alert_mutex);
|
||||
|
||||
kis_alert_info *info = new kis_alert_info;
|
||||
|
||||
info->header = in_header;
|
||||
info->phy = in_phy;
|
||||
gettimeofday(&(info->tm), NULL);
|
||||
|
||||
info->bssid = mac_addr(0);
|
||||
info->source = mac_addr(0);
|
||||
info->dest = mac_addr(0);
|
||||
info->other = mac_addr(0);
|
||||
|
||||
info->channel = "";
|
||||
|
||||
info->text = in_text;
|
||||
|
||||
lock.lock();
|
||||
alert_backlog.push_back(info);
|
||||
if ((int) alert_backlog.size() > num_backlog) {
|
||||
delete alert_backlog[0];
|
||||
alert_backlog.erase(alert_backlog.begin());
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
#ifdef PRELUDE
|
||||
// Send alert to Prelude
|
||||
RaisePreludeOneShot(in_header, in_text);
|
||||
#endif
|
||||
|
||||
// Send the text info
|
||||
_MSG(info->header + " " + info->text, MSGFLAG_ALERT);
|
||||
|
||||
if (log_alerts) {
|
||||
auto dbf =
|
||||
Globalreg::FetchGlobalAs<KisDatabaseLogfile>("DATABASELOG");
|
||||
if (dbf != NULL) {
|
||||
auto ta = std::make_shared<tracked_alert>(alert_entry_id);
|
||||
ta->from_alert_info(info);
|
||||
dbf->log_alert(ta);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Alertracker::RaisePreludeAlert(int in_ref, kis_packet *in_pack,
|
||||
mac_addr bssid, mac_addr source, mac_addr dest,
|
||||
mac_addr other, std::string in_channel, std::string in_text) {
|
||||
|
||||
#ifdef PRELUDE
|
||||
mac_addr emptymac = mac_addr(0);
|
||||
|
||||
Prelude::IDMEF idmef;
|
||||
|
||||
// Classification
|
||||
idmef.set("alert.classification.text", "Suspicious network detected");
|
||||
|
||||
// Source
|
||||
if (source != emptymac) {
|
||||
idmef.set("alert.source(0).node.address(0).category", "mac");
|
||||
idmef.set("alert.source(0).node.address(0).address", source.Mac2String().c_str());
|
||||
}
|
||||
|
||||
// Target
|
||||
if (dest != emptymac) {
|
||||
idmef.set("alert.target(0).node.address(0).category", "mac");
|
||||
idmef.set("alert.target(0).node.address(0).address", dest.Mac2String().c_str());
|
||||
}
|
||||
|
||||
// Assessment
|
||||
idmef.set("alert.assessment.impact.severity", "high");
|
||||
idmef.set("alert.assessment.impact.completion", "succeeded");
|
||||
idmef.set("alert.assessment.impact.description", in_text);
|
||||
|
||||
// Additional Data
|
||||
if (bssid != emptymac) {
|
||||
idmef.set("alert.additional_data(>>).meaning", "BSSID");
|
||||
idmef.set("alert.additional_data(-1).data", bssid.Mac2String().c_str());
|
||||
}
|
||||
|
||||
if (other != emptymac) {
|
||||
idmef.set("alert.additional_data(>>).meaning", "Other");
|
||||
idmef.set("alert.additional_data(-1).data", other.Mac2String().c_str());
|
||||
}
|
||||
|
||||
idmef.set("alert.additional_data(>>).meaning", "Channel");
|
||||
idmef.set("alert.additional_data(-1).data", in_channel);
|
||||
|
||||
idmef.set("alert.additional_data(>>).meaning", "in_ref");
|
||||
idmef.set("alert.additional_data(-1).data", in_ref);
|
||||
|
||||
prelude_client->sendIDMEF(idmef);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Alertracker::RaisePreludeOneShot(std::string in_header, std::string in_text) {
|
||||
#ifdef PRELUDE
|
||||
mac_addr emptymac = mac_addr(0);
|
||||
|
||||
Prelude::IDMEF idmef;
|
||||
|
||||
// Classification
|
||||
idmef.set("alert.classification.text", "Suspicious network detected");
|
||||
|
||||
// Assessment
|
||||
idmef.set("alert.assessment.impact.severity", "high");
|
||||
idmef.set("alert.assessment.impact.completion", "succeeded");
|
||||
idmef.set("alert.assessment.impact.description", in_text);
|
||||
|
||||
idmef.set("alert.additional_data(>>).alert_type", "in_ref");
|
||||
idmef.set("alert.additional_data(-1).data", in_header);
|
||||
|
||||
prelude_client->sendIDMEF(idmef);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Alertracker::ParseAlertStr(std::string alert_str, std::string *ret_name,
|
||||
alert_time_unit *ret_limit_unit, int *ret_limit_rate,
|
||||
alert_time_unit *ret_limit_burst,
|
||||
int *ret_burst_rate) {
|
||||
|
||||
std::vector<std::string> tokens = StrTokenize(alert_str, ",");
|
||||
|
||||
if (tokens.size() != 3) {
|
||||
_MSG_ERROR("Malformed limits for alert '{}'", alert_str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
(*ret_name) = StrUpper(tokens[0]);
|
||||
|
||||
if (ParseRateUnit(StrLower(tokens[1]), ret_limit_unit, ret_limit_rate) != 1 ||
|
||||
ParseRateUnit(StrLower(tokens[2]), ret_limit_burst, ret_burst_rate) != 1) {
|
||||
_MSG_ERROR("Malformed limits for alert '{}'", alert_str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Split up a rate/unit string into real values
|
||||
int Alertracker::ParseRateUnit(std::string in_ru, alert_time_unit *ret_unit,
|
||||
int *ret_rate) {
|
||||
std::vector<std::string> units = StrTokenize(in_ru, "/");
|
||||
|
||||
if (units.size() == 1) {
|
||||
// Unit is per minute if not specified
|
||||
(*ret_unit) = sat_minute;
|
||||
} else {
|
||||
// Parse the string unit
|
||||
if (units[1] == "sec" || units[1] == "second") {
|
||||
(*ret_unit) = sat_second;
|
||||
} else if (units[1] == "min" || units[1] == "minute") {
|
||||
(*ret_unit) = sat_minute;
|
||||
} else if (units[1] == "hr" || units[1] == "hour") {
|
||||
(*ret_unit) = sat_hour;
|
||||
} else if (units[1] == "day") {
|
||||
(*ret_unit) = sat_day;
|
||||
} else {
|
||||
_MSG("Invalid time unit for alert rate '" + units[1] + "'",
|
||||
MSGFLAG_ERROR);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the number
|
||||
if (sscanf(units[0].c_str(), "%d", ret_rate) != 1) {
|
||||
_MSG("Invalid rate '" + units[0] + "' for alert", MSGFLAG_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Alertracker::ParseAlertConfig(ConfigFile *in_conf) {
|
||||
std::vector<std::string> clines = in_conf->FetchOptVec("alert");
|
||||
|
||||
for (unsigned int x = 0; x < clines.size(); x++) {
|
||||
alert_conf_rec *rec = new alert_conf_rec;
|
||||
|
||||
if (ParseAlertStr(clines[x], &(rec->header), &(rec->limit_unit),
|
||||
&(rec->limit_rate), &(rec->burst_unit),
|
||||
&(rec->limit_burst)) < 0) {
|
||||
_MSG_FATAL("Invalid 'alert' config option {}; expected HEADER,rate,burstrate", clines[x]);
|
||||
Globalreg::globalreg->fatal_condition = 1;
|
||||
delete rec;
|
||||
return -1;
|
||||
}
|
||||
|
||||
alert_conf_map.insert(std::make_pair(rec->header, rec));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Alertracker::DefineAlert(std::string name, alert_time_unit limit_unit, int limit_rate,
|
||||
alert_time_unit burst_unit, int burst_rate) {
|
||||
local_locker lock(&alert_mutex);
|
||||
|
||||
auto ai = alert_conf_map.find(StrUpper(name));
|
||||
if (ai != alert_conf_map.end()) {
|
||||
_MSG_ERROR("alerttracker - tried to define alert '{}' twice.", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
alert_conf_rec *rec = new alert_conf_rec;
|
||||
rec->header = StrUpper(name);
|
||||
rec->limit_unit = limit_unit;
|
||||
rec->limit_rate = limit_rate;
|
||||
rec->burst_unit = burst_unit;
|
||||
rec->limit_burst = burst_rate;
|
||||
|
||||
alert_conf_map.insert(std::make_pair(rec->header, rec));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Alertracker::ActivateConfiguredAlert(std::string in_header, std::string in_desc) {
|
||||
return ActivateConfiguredAlert(in_header, in_desc, KIS_PHY_UNKNOWN);
|
||||
}
|
||||
|
||||
int Alertracker::ActivateConfiguredAlert(std::string in_header, std::string in_desc, int in_phy) {
|
||||
alert_conf_rec *rec;
|
||||
|
||||
{
|
||||
local_locker lock(&alert_mutex);
|
||||
|
||||
std::string hdr = StrUpper(in_header);
|
||||
|
||||
auto hi = alert_conf_map.find(hdr);
|
||||
|
||||
if (hi == alert_conf_map.end()) {
|
||||
_MSG_INFO("Using default rates of 10/min, 1/sec for alert '{}'", in_header);
|
||||
DefineAlert(in_header, sat_minute, 10, sat_second, 1);
|
||||
|
||||
auto hi_full = alert_conf_map.find(hdr);
|
||||
if (hi_full == alert_conf_map.end()) {
|
||||
_MSG_ERROR("Failed to define default rate alert '{}'", in_header);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rec = hi_full->second;
|
||||
} else {
|
||||
rec = hi->second;
|
||||
}
|
||||
}
|
||||
|
||||
return RegisterAlert(rec->header, in_desc, rec->limit_unit, rec->limit_rate,
|
||||
rec->burst_unit, rec->limit_burst, in_phy);
|
||||
}
|
||||
|
||||
int Alertracker::FindActivatedAlert(std::string in_header) {
|
||||
local_locker lock(&alert_mutex);
|
||||
|
||||
for (auto x : alert_ref_map) {
|
||||
if (x.second->get_header() == in_header)
|
||||
return x.first;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool Alertracker::Httpd_VerifyPath(const char *path, const char *method) {
|
||||
if (!Httpd_CanSerialize(path))
|
||||
return false;
|
||||
|
||||
if (strcmp(method, "GET") == 0) {
|
||||
// Split URL and process
|
||||
std::vector<std::string> tokenurl = StrTokenize(path, "/");
|
||||
if (tokenurl.size() < 3)
|
||||
return false;
|
||||
|
||||
if (tokenurl[1] == "alerts") {
|
||||
if (Httpd_StripSuffix(tokenurl[2]) == "definitions") {
|
||||
return true;
|
||||
} else if (Httpd_StripSuffix(tokenurl[2]) == "all_alerts") {
|
||||
return true;
|
||||
} else if (tokenurl[2] == "last-time") {
|
||||
if (tokenurl.size() < 5)
|
||||
return false;
|
||||
|
||||
if (Httpd_CanSerialize(tokenurl[4]))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(method, "POST") == 0) {
|
||||
std::string stripped = httpd->StripSuffix(path);
|
||||
|
||||
if (stripped == "/alerts/definitions/define_alert")
|
||||
return true;
|
||||
|
||||
if (stripped == "/alerts/raise_alert")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Alertracker::Httpd_CreateStreamResponse(
|
||||
Kis_Net_Httpd *httpd __attribute__((unused)),
|
||||
Kis_Net_Httpd_Connection *connection,
|
||||
const char *path, const char *method, const char *upload_data,
|
||||
size_t *upload_data_size, std::stringstream &stream) {
|
||||
|
||||
double since_time = 0;
|
||||
bool wrap = false;
|
||||
|
||||
if (strcmp(method, "GET") != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Httpd_CanSerialize(path))
|
||||
return;
|
||||
|
||||
// Split URL and process
|
||||
std::vector<std::string> tokenurl = StrTokenize(path, "/");
|
||||
if (tokenurl.size() < 3)
|
||||
return;
|
||||
|
||||
if (tokenurl[1] == "alerts") {
|
||||
if (Httpd_StripSuffix(tokenurl[2]) == "definitions") {
|
||||
Httpd_Serialize(path, stream, alert_defs_vec);
|
||||
return;
|
||||
} else if (tokenurl[2] == "last-time") {
|
||||
if (tokenurl.size() < 5)
|
||||
return;
|
||||
|
||||
std::stringstream ss(tokenurl[3]);
|
||||
ss >> since_time;
|
||||
|
||||
wrap = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<TrackerElement> transmit;
|
||||
std::shared_ptr<TrackerElementMap> wrapper;
|
||||
std::shared_ptr<TrackerElementVector> msgvec = std::make_shared<TrackerElementVector>(alert_vec_id);
|
||||
|
||||
// If we're doing a time-since, wrap the vector
|
||||
if (wrap) {
|
||||
wrapper = std::make_shared<TrackerElementMap>();
|
||||
wrapper->insert(msgvec);
|
||||
|
||||
auto ts = std::make_shared<TrackerElementDouble>(alert_timestamp_id, ts_now_to_double());
|
||||
wrapper->insert(ts);
|
||||
|
||||
transmit = wrapper;
|
||||
} else {
|
||||
transmit = msgvec;
|
||||
}
|
||||
|
||||
{
|
||||
local_locker lock(&alert_mutex);
|
||||
|
||||
for (auto i : alert_backlog) {
|
||||
if (since_time < ts_to_double((i)->tm)) {
|
||||
auto ta = std::make_shared<tracked_alert>(alert_entry_id);
|
||||
ta->from_alert_info(i);
|
||||
msgvec->push_back(ta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Httpd_Serialize(path, stream, transmit);
|
||||
}
|
||||
|
||||
int Alertracker::Httpd_PostComplete(Kis_Net_Httpd_Connection *concls) {
|
||||
std::string stripped = Httpd_StripSuffix(concls->url);
|
||||
|
||||
if (!Httpd_CanSerialize(concls->url) ||
|
||||
(stripped != "/alerts/definitions/define_alert" &&
|
||||
stripped != "/alerts/raise_alert")) {
|
||||
concls->response_stream << "Invalid request";
|
||||
concls->httpcode = 400;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!httpd->HasValidSession(concls, true)) {
|
||||
concls->httpcode = 503;
|
||||
return MHD_NO;
|
||||
}
|
||||
|
||||
SharedStructured structdata;
|
||||
|
||||
try {
|
||||
if (concls->variable_cache.find("json") != concls->variable_cache.end()) {
|
||||
structdata.reset(new StructuredJson(concls->variable_cache["json"]->str()));
|
||||
} else {
|
||||
throw std::runtime_error("could not find data");
|
||||
}
|
||||
|
||||
if (stripped == "/alerts/definitions/define_alert") {
|
||||
std::string name = structdata->getKeyAsString("name");
|
||||
std::string desc = structdata->getKeyAsString("description");
|
||||
|
||||
alert_time_unit limit_unit;
|
||||
int limit_rate;
|
||||
|
||||
alert_time_unit burst_unit;
|
||||
int burst_rate;
|
||||
|
||||
if (ParseRateUnit(StrLower(structdata->getKeyAsString("throttle", "")),
|
||||
&limit_unit, &limit_rate) < 0) {
|
||||
throw std::runtime_error("could not parse throttle limits");
|
||||
}
|
||||
|
||||
if (ParseRateUnit(StrLower(structdata->getKeyAsString("burst", "")),
|
||||
&burst_unit, &burst_rate) < 0) {
|
||||
throw std::runtime_error("could not parse burst limits");
|
||||
}
|
||||
|
||||
int phyid = KIS_PHY_ANY;
|
||||
|
||||
std::string phyname = structdata->getKeyAsString("phyname", "");
|
||||
|
||||
if (phyname != "any" && phyname != "") {
|
||||
auto devicetracker =
|
||||
Globalreg::FetchMandatoryGlobalAs<Devicetracker>();
|
||||
Kis_Phy_Handler *phyh = devicetracker->FetchPhyHandlerByName(phyname);
|
||||
|
||||
if (phyh == NULL)
|
||||
throw std::runtime_error("could not find phy");
|
||||
|
||||
phyid = phyh->FetchPhyId();
|
||||
}
|
||||
|
||||
if (DefineAlert(name, limit_unit, limit_rate, burst_unit, burst_rate) < 0) {
|
||||
concls->httpcode = 503;
|
||||
throw std::runtime_error("could not add alert");
|
||||
}
|
||||
|
||||
if (ActivateConfiguredAlert(name, desc, phyid) < 0) {
|
||||
concls->httpcode = 504;
|
||||
throw std::runtime_error("could not activate alert");
|
||||
}
|
||||
|
||||
concls->response_stream << "Added alert";
|
||||
return 1;
|
||||
|
||||
} else if (stripped == "/alerts/raise_alert") {
|
||||
std::string name = structdata->getKeyAsString("name");
|
||||
|
||||
int aref = FetchAlertRef(name);
|
||||
|
||||
if (aref < 0)
|
||||
throw std::runtime_error("unknown alert type");
|
||||
|
||||
std::string text = structdata->getKeyAsString("text");
|
||||
|
||||
std::string bssid = structdata->getKeyAsString("bssid", "");
|
||||
std::string source = structdata->getKeyAsString("source", "");
|
||||
std::string dest = structdata->getKeyAsString("dest", "");
|
||||
std::string other = structdata->getKeyAsString("other", "");
|
||||
std::string channel = structdata->getKeyAsString("channel", "");
|
||||
|
||||
mac_addr bssid_mac, source_mac, dest_mac, other_mac;
|
||||
|
||||
if (bssid.length() != 0) {
|
||||
bssid_mac = mac_addr(bssid);
|
||||
}
|
||||
if (source.length() != 0) {
|
||||
source_mac = mac_addr(source);
|
||||
}
|
||||
if (dest.length() != 0) {
|
||||
dest_mac = mac_addr(dest);
|
||||
}
|
||||
if (other.length() != 0) {
|
||||
other_mac = mac_addr(other);
|
||||
}
|
||||
|
||||
if (bssid_mac.error || source_mac.error ||
|
||||
dest_mac.error || other_mac.error) {
|
||||
throw std::runtime_error("invalid mac");
|
||||
}
|
||||
|
||||
if (!PotentialAlert(aref))
|
||||
throw std::runtime_error("alert limit reached");
|
||||
|
||||
RaiseAlert(aref, NULL, bssid_mac, source_mac, dest_mac, other_mac,
|
||||
channel, text);
|
||||
|
||||
concls->response_stream << "alert raised";
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
concls->response_stream << "Invalid request " << e.what();
|
||||
|
||||
if (concls->httpcode != 200)
|
||||
concls->httpcode = 400;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return MHD_NO;
|
||||
}
|
||||
|
||||
|
|
@ -1,437 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __ALERTRACKER_H__
|
||||
#define __ALERTRACKER_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "globalregistry.h"
|
||||
#include "kis_mutex.h"
|
||||
#include "messagebus.h"
|
||||
#include "packetchain.h"
|
||||
#include "timetracker.h"
|
||||
#include "kis_net_microhttpd.h"
|
||||
#include "kis_gps.h"
|
||||
|
||||
#ifdef PRELUDE
|
||||
#include <libprelude/prelude.hxx>
|
||||
#define PRELUDE_ANALYZER_MODEL "Kismet"
|
||||
#define PRELUDE_ANALYZER_CLASS "Wireless Monitor"
|
||||
#define PRELUDE_ANALYZER_MANUFACTURER "https://www.kismetwireless.net/"
|
||||
#endif
|
||||
|
||||
// TODO:
|
||||
// - move packet_component to a tracked system & just use the converted
|
||||
// kis_alert_info in the future...
|
||||
// - Move alert_ref into a tracked component and return via rest
|
||||
// - Add description to alerts
|
||||
|
||||
class kis_alert_info : public packet_component {
|
||||
public:
|
||||
kis_alert_info() {
|
||||
tm.tv_sec = 0;
|
||||
tm.tv_usec = 0;
|
||||
channel = "0";
|
||||
|
||||
gps = NULL;
|
||||
|
||||
// We do NOT self-destruct because we get cached in the alertracker
|
||||
// for playbacks. It's responsible for discarding us
|
||||
self_destruct = 0;
|
||||
}
|
||||
|
||||
virtual ~kis_alert_info() {
|
||||
if (gps != NULL)
|
||||
delete(gps);
|
||||
}
|
||||
|
||||
device_key devicekey;
|
||||
|
||||
std::string header;
|
||||
int phy;
|
||||
struct timeval tm;
|
||||
mac_addr bssid;
|
||||
mac_addr source;
|
||||
mac_addr dest;
|
||||
mac_addr other;
|
||||
std::string channel;
|
||||
std::string text;
|
||||
|
||||
kis_gps_packinfo *gps;
|
||||
};
|
||||
|
||||
class kis_alert_component : public packet_component {
|
||||
public:
|
||||
kis_alert_component() {
|
||||
// We can self destruct because we won't clear out the vector
|
||||
// of actual alert info
|
||||
self_destruct = 1;
|
||||
}
|
||||
|
||||
std::vector<kis_alert_info *> alert_vec;
|
||||
};
|
||||
|
||||
class tracked_alert : public tracker_component {
|
||||
public:
|
||||
tracked_alert() :
|
||||
tracker_component() {
|
||||
register_fields();
|
||||
reserve_fields(NULL);
|
||||
}
|
||||
|
||||
tracked_alert(int in_id) :
|
||||
tracker_component(in_id) {
|
||||
register_fields();
|
||||
reserve_fields(NULL);
|
||||
}
|
||||
|
||||
tracked_alert(int in_id, std::shared_ptr<TrackerElementMap> e) :
|
||||
tracker_component(in_id) {
|
||||
register_fields();
|
||||
reserve_fields(e);
|
||||
}
|
||||
|
||||
virtual uint32_t get_signature() const override {
|
||||
return Adler32Checksum("tracked_alert");
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<TrackerElement> clone_type() override {
|
||||
using this_t = std::remove_pointer<decltype(this)>::type;
|
||||
auto dup = std::unique_ptr<this_t>(new this_t());
|
||||
return std::move(dup);
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<TrackerElement> clone_type(int in_id) override {
|
||||
using this_t = std::remove_pointer<decltype(this)>::type;
|
||||
auto dup = std::unique_ptr<this_t>(new this_t(in_id));
|
||||
return std::move(dup);
|
||||
}
|
||||
|
||||
__Proxy(devicekey, device_key, device_key, device_key, devicekey);
|
||||
|
||||
__Proxy(header, std::string, std::string, std::string, header);
|
||||
__Proxy(phy, uint32_t, uint32_t, uint32_t, phy);
|
||||
__Proxy(timestamp, double, double, double, timestamp);
|
||||
|
||||
__Proxy(transmitter_mac, mac_addr, mac_addr, mac_addr, transmitter_mac);
|
||||
__Proxy(source_mac, mac_addr, mac_addr, mac_addr, source_mac);
|
||||
__Proxy(dest_mac, mac_addr, mac_addr, mac_addr, dest_mac);
|
||||
__Proxy(other_mac, mac_addr, mac_addr, mac_addr, other_mac);
|
||||
|
||||
__Proxy(channel, std::string, std::string, std::string, channel);
|
||||
__Proxy(frequency, double, double, double, frequency);
|
||||
|
||||
__Proxy(text, std::string, std::string, std::string, text);
|
||||
|
||||
__ProxyTrackable(location, kis_tracked_location_triplet, location);
|
||||
|
||||
void from_alert_info(kis_alert_info *info) {
|
||||
set_devicekey(info->devicekey);
|
||||
set_header(info->header);
|
||||
set_phy(info->phy);
|
||||
set_timestamp(ts_to_double(info->tm));
|
||||
set_transmitter_mac(info->bssid);
|
||||
set_source_mac(info->source);
|
||||
set_dest_mac(info->dest);
|
||||
set_other_mac(info->other);
|
||||
set_channel(info->channel);
|
||||
set_text(info->text);
|
||||
|
||||
if (info->gps != NULL)
|
||||
location->set(info->gps);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void register_fields() override {
|
||||
tracker_component::register_fields();
|
||||
|
||||
RegisterField("kismet.alert.device_key", "Device key of linked device", &devicekey);
|
||||
RegisterField("kismet.alert.header", "Alert type", &header);
|
||||
RegisterField("kismet.alert.phy_id", "ID of phy generating alert", &phy);
|
||||
RegisterField("kismet.alert.timestamp", "Timestamp (sec.ms)", ×tamp);
|
||||
RegisterField("kismet.alert.transmitter_mac", "Transmitter MAC address", &transmitter_mac);
|
||||
RegisterField("kismet.alert.source_mac", "Source MAC address", &source_mac);
|
||||
RegisterField("kismet.alert.dest_mac", "Destination MAC address", &dest_mac);
|
||||
RegisterField("kismet.alert.other_mac", "Other / Extra MAC address", &other_mac);
|
||||
RegisterField("kismet.alert.channel", "Phy-specific channel", &channel);
|
||||
RegisterField("kismet.alert.frequency", "Frequency (khz)", &frequency);
|
||||
RegisterField("kismet.alert.text", "Alert text", &text);
|
||||
RegisterField("kismet.alert.location", "location", &location);
|
||||
}
|
||||
|
||||
std::shared_ptr<TrackerElementDeviceKey> devicekey;
|
||||
std::shared_ptr<TrackerElementString> header;
|
||||
std::shared_ptr<TrackerElementUInt32> phy;
|
||||
std::shared_ptr<TrackerElementDouble> timestamp;
|
||||
std::shared_ptr<TrackerElementMacAddr> transmitter_mac;
|
||||
std::shared_ptr<TrackerElementMacAddr> source_mac;
|
||||
std::shared_ptr<TrackerElementMacAddr> dest_mac;
|
||||
std::shared_ptr<TrackerElementMacAddr> other_mac;
|
||||
std::shared_ptr<TrackerElementString> channel;
|
||||
std::shared_ptr<TrackerElementDouble> frequency;
|
||||
std::shared_ptr<TrackerElementString> text;
|
||||
std::shared_ptr<kis_tracked_location_triplet> location;
|
||||
};
|
||||
|
||||
|
||||
static const int alert_time_unit_conv[] = {
|
||||
1, 60, 3600, 86400
|
||||
};
|
||||
|
||||
enum alert_time_unit {
|
||||
sat_second, sat_minute, sat_hour, sat_day
|
||||
};
|
||||
|
||||
class tracked_alert_definition : public tracker_component {
|
||||
public:
|
||||
tracked_alert_definition() :
|
||||
tracker_component() {
|
||||
register_fields();
|
||||
reserve_fields(NULL);
|
||||
}
|
||||
|
||||
tracked_alert_definition(int in_id) :
|
||||
tracker_component(in_id) {
|
||||
register_fields();
|
||||
reserve_fields(NULL);
|
||||
}
|
||||
|
||||
tracked_alert_definition(int in_id, std::shared_ptr<TrackerElementMap> e) :
|
||||
tracker_component(in_id) {
|
||||
register_fields();
|
||||
reserve_fields(e);
|
||||
}
|
||||
|
||||
virtual uint32_t get_signature() const override {
|
||||
return Adler32Checksum("tracked_alert_definition");
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<TrackerElement> clone_type() override {
|
||||
using this_t = std::remove_pointer<decltype(this)>::type;
|
||||
auto dup = std::unique_ptr<this_t>(new this_t());
|
||||
return std::move(dup);
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<TrackerElement> clone_type(int in_id) override {
|
||||
using this_t = std::remove_pointer<decltype(this)>::type;
|
||||
auto dup = std::unique_ptr<this_t>(new this_t(in_id));
|
||||
return std::move(dup);
|
||||
}
|
||||
|
||||
__Proxy(header, std::string, std::string, std::string, header);
|
||||
__Proxy(description, std::string, std::string, std::string, description);
|
||||
__Proxy(phy, int64_t, int64_t, int64_t, phy);
|
||||
|
||||
__Proxy(limit_unit, uint64_t, alert_time_unit, alert_time_unit, limit_unit);
|
||||
__Proxy(limit_rate, uint64_t, uint64_t, uint64_t, limit_rate);
|
||||
|
||||
__Proxy(burst_unit, uint64_t, alert_time_unit, alert_time_unit, burst_unit);
|
||||
__Proxy(limit_burst, uint64_t, uint64_t, uint64_t, limit_burst);
|
||||
|
||||
__Proxy(burst_sent, uint64_t, uint64_t, uint64_t, burst_sent);
|
||||
__ProxyIncDec(burst_sent, uint64_t, uint64_t, burst_sent);
|
||||
|
||||
__Proxy(total_sent, uint64_t, uint64_t, uint64_t, total_sent);
|
||||
__ProxyIncDec(total_sent, uint64_t, uint64_t, total_sent);
|
||||
|
||||
__Proxy(time_last, double, double, double, time_last);
|
||||
|
||||
int get_alert_ref() { return alert_ref; }
|
||||
void set_alert_ref(int in_ref) { alert_ref = in_ref; }
|
||||
|
||||
protected:
|
||||
virtual void register_fields() override {
|
||||
tracker_component::register_fields();
|
||||
|
||||
RegisterField("kismet.alert.definition.header", "Alert type", &header);
|
||||
RegisterField("kismet.alert.definition.description", "Alert description", &description);
|
||||
RegisterField("kismet.alert.definition.phyid", "Alert phy type", &phy);
|
||||
RegisterField("kismet.alert.definition.limit_unit",
|
||||
"Alert limit time unit (defined in alertracker.h)", &limit_unit);
|
||||
RegisterField("kismet.alert.definition.limit_rate", "Alert rate limit", &limit_rate);
|
||||
RegisterField("kismet.alert.definition.burst_unit",
|
||||
"Burst limit time unit (defined in alertracker.h)", &burst_unit);
|
||||
RegisterField("kismet.alert.definition.limit_burst", "Burst rate limit", &limit_burst);
|
||||
RegisterField("kismet.alert.definition.burst_sent", "Alerts sent in burst", &burst_sent);
|
||||
RegisterField("kismet.alert.definition.total_sent", "Total alerts sent", &total_sent);
|
||||
RegisterField("kismet.alert.definition.time_last",
|
||||
"Timestamp of last alert (sec.us)", &time_last);
|
||||
}
|
||||
|
||||
// Non-exposed internal reference
|
||||
int alert_ref;
|
||||
|
||||
// Alert type and description
|
||||
std::shared_ptr<TrackerElementString> header;
|
||||
std::shared_ptr<TrackerElementString> description;
|
||||
// Phynum this is linked to
|
||||
std::shared_ptr<TrackerElementInt64> phy;
|
||||
|
||||
// Units, rate limit, burst, and burst rate
|
||||
std::shared_ptr<TrackerElementUInt64> limit_unit;
|
||||
std::shared_ptr<TrackerElementUInt64> limit_rate;
|
||||
std::shared_ptr<TrackerElementUInt64> burst_unit;
|
||||
std::shared_ptr<TrackerElementUInt64> limit_burst;
|
||||
|
||||
// Number of burst and total alerts we've sent of this type
|
||||
std::shared_ptr<TrackerElementUInt64> burst_sent;
|
||||
std::shared_ptr<TrackerElementUInt64> total_sent;
|
||||
|
||||
// Timestamp of the last time
|
||||
std::shared_ptr<TrackerElementDouble> time_last;
|
||||
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<tracked_alert_definition> shared_alert_def;
|
||||
|
||||
class Alertracker : public Kis_Net_Httpd_CPPStream_Handler, public LifetimeGlobal {
|
||||
public:
|
||||
// Simple struct from reading config lines
|
||||
struct alert_conf_rec {
|
||||
std::string header;
|
||||
alert_time_unit limit_unit;
|
||||
int limit_rate;
|
||||
alert_time_unit burst_unit;
|
||||
int limit_burst;
|
||||
};
|
||||
|
||||
static std::string global_name() { return "ALERTTRACKER"; }
|
||||
|
||||
static std::shared_ptr<Alertracker> create_alertracker() {
|
||||
std::shared_ptr<Alertracker> mon(new Alertracker());
|
||||
Globalreg::globalreg->alertracker = mon.get();
|
||||
Globalreg::globalreg->RegisterLifetimeGlobal(mon);
|
||||
Globalreg::globalreg->InsertGlobal(global_name(), mon);
|
||||
return mon;
|
||||
}
|
||||
|
||||
private:
|
||||
Alertracker();
|
||||
|
||||
// Raise an Prelude alert (requires prelude support compiled in)
|
||||
int RaisePreludeAlert(int in_ref, kis_packet *in_pack, mac_addr bssid, mac_addr source,
|
||||
mac_addr dest, mac_addr other, std::string in_channel, std::string in_text);
|
||||
int RaisePreludeOneShot(std::string in_header, std::string in_text);
|
||||
|
||||
// Initialize Prelude Client (requires prelude support compiled in)
|
||||
void PreludeInitClient(const char *analyzer_name);
|
||||
|
||||
public:
|
||||
virtual ~Alertracker();
|
||||
|
||||
// Register an alert and get an alert reference number back.
|
||||
int RegisterAlert(std::string in_header, std::string in_desc,
|
||||
alert_time_unit in_unit, int in_rate, alert_time_unit in_burstunit,
|
||||
int in_burst, int in_phy);
|
||||
|
||||
// Find a reference from a name
|
||||
int FetchAlertRef(std::string in_header);
|
||||
|
||||
// Will an alert succeed?
|
||||
int PotentialAlert(int in_ref);
|
||||
|
||||
// Raise an alert ...
|
||||
int RaiseAlert(int in_ref, kis_packet *in_pack,
|
||||
mac_addr bssid, mac_addr source, mac_addr dest, mac_addr other,
|
||||
std::string in_channel, std::string in_text);
|
||||
|
||||
// Raise a one-shot communications alert
|
||||
int RaiseOneShot(std::string in_header, std::string in_text, int in_phy);
|
||||
|
||||
// parse an alert config string
|
||||
int ParseAlertStr(std::string alert_str, std::string *ret_name,
|
||||
alert_time_unit *ret_limit_unit, int *ret_limit_rate,
|
||||
alert_time_unit *ret_limit_burst, int *ret_burst_rate);
|
||||
|
||||
// Load alert rates from a config file
|
||||
int ParseAlertConfig(ConfigFile *in_conf);
|
||||
|
||||
// Define an alert and limits
|
||||
int DefineAlert(std::string name, alert_time_unit limit_unit, int limit_rate,
|
||||
alert_time_unit limit_burst, int burst_rate);
|
||||
|
||||
// Activate a preconfigured alert from a file
|
||||
int ActivateConfiguredAlert(std::string in_header, std::string in_desc);
|
||||
int ActivateConfiguredAlert(std::string in_header, std::string in_desc, int in_phy);
|
||||
|
||||
// Find an activated alert
|
||||
int FindActivatedAlert(std::string in_header);
|
||||
|
||||
virtual bool Httpd_VerifyPath(const char *path, const char *method);
|
||||
|
||||
virtual void Httpd_CreateStreamResponse(Kis_Net_Httpd *httpd,
|
||||
Kis_Net_Httpd_Connection *connection,
|
||||
const char *url, const char *method, const char *upload_data,
|
||||
size_t *upload_data_size, std::stringstream &stream);
|
||||
|
||||
virtual int Httpd_PostComplete(Kis_Net_Httpd_Connection *concls);
|
||||
|
||||
protected:
|
||||
kis_recursive_timed_mutex alert_mutex;
|
||||
|
||||
std::shared_ptr<Packetchain> packetchain;
|
||||
std::shared_ptr<EntryTracker> entrytracker;
|
||||
|
||||
int alert_vec_id, alert_entry_id, alert_timestamp_id, alert_def_id;
|
||||
|
||||
// Check and age times
|
||||
int CheckTimes(shared_alert_def arec);
|
||||
|
||||
// Parse a foo/bar rate/unit option
|
||||
int ParseRateUnit(std::string in_ru, alert_time_unit *ret_unit, int *ret_rate);
|
||||
|
||||
int pack_comp_alert;
|
||||
int alert_ref_kismet;
|
||||
|
||||
int next_alert_id;
|
||||
|
||||
// Internal C++ mapping
|
||||
std::map<std::string, int> alert_name_map;
|
||||
std::map<int, shared_alert_def> alert_ref_map;
|
||||
|
||||
// Tracked mapping for export
|
||||
std::shared_ptr<TrackerElementVector> alert_defs_vec;
|
||||
|
||||
int num_backlog;
|
||||
|
||||
// Backlog of alerts to be sent
|
||||
std::vector<kis_alert_info *> alert_backlog;
|
||||
|
||||
// Alert configs we read before we know the alerts themselves
|
||||
std::map<std::string, alert_conf_rec *> alert_conf_map;
|
||||
|
||||
#ifdef PRELUDE
|
||||
// Prelude client
|
||||
Prelude::ClientEasy *prelude_client;
|
||||
#endif
|
||||
|
||||
// Do we log alerts to the kismet database?
|
||||
bool log_alerts;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,459 +0,0 @@
|
|||
#ifndef ALPHANUM__HPP
|
||||
#define ALPHANUM__HPP
|
||||
|
||||
/*
|
||||
The Alphanum Algorithm is an improved sorting algorithm for strings
|
||||
containing numbers. Instead of sorting numbers in ASCII order like a
|
||||
standard sort, this algorithm sorts numbers in numeric order.
|
||||
|
||||
The Alphanum Algorithm is discussed at http://www.DaveKoelle.com
|
||||
|
||||
This implementation is Copyright (c) 2008 Dirk Jagdmann <doj@cubic.org>.
|
||||
It is a cleanroom implementation of the algorithm and not derived by
|
||||
other's works. In contrast to the versions written by Dave Koelle this
|
||||
source code is distributed with the libpng/zlib license.
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you
|
||||
must not claim that you wrote the original software. If you use
|
||||
this software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and
|
||||
must not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution. */
|
||||
|
||||
/* $Header: /code/doj/alphanum.hpp,v 1.3 2008/01/28 23:06:47 doj Exp $ */
|
||||
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef ALPHANUM_LOCALE
|
||||
#include <cctype>
|
||||
#endif
|
||||
|
||||
#ifdef DOJDEBUG
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
#endif
|
||||
|
||||
// TODO: make comparison with hexadecimal numbers. Extend the alphanum_comp() function by traits to choose between decimal and hexadecimal.
|
||||
|
||||
namespace doj
|
||||
{
|
||||
|
||||
// anonymous namespace for functions we use internally. But if you
|
||||
// are coding in C, you can use alphanum_impl() directly, since it
|
||||
// uses not C++ features.
|
||||
namespace {
|
||||
|
||||
// if you want to honour the locale settings for detecting digit
|
||||
// characters, you should define ALPHANUM_LOCALE
|
||||
#ifdef ALPHANUM_LOCALE
|
||||
/** wrapper function for ::isdigit() */
|
||||
bool alphanum_isdigit(int c)
|
||||
{
|
||||
return isdigit(c);
|
||||
}
|
||||
#else
|
||||
/** this function does not consider the current locale and only
|
||||
works with ASCII digits.
|
||||
@return true if c is a digit character
|
||||
*/
|
||||
bool alphanum_isdigit(const char c)
|
||||
{
|
||||
return c>='0' && c<='9';
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
compare l and r with strcmp() semantics, but using
|
||||
the "Alphanum Algorithm". This function is designed to read
|
||||
through the l and r strings only one time, for
|
||||
maximum performance. It does not allocate memory for
|
||||
substrings. It can either use the C-library functions isdigit()
|
||||
and atoi() to honour your locale settings, when recognizing
|
||||
digit characters when you "#define ALPHANUM_LOCALE=1" or use
|
||||
it's own digit character handling which only works with ASCII
|
||||
digit characters, but provides better performance.
|
||||
|
||||
@param l NULL-terminated C-style string
|
||||
@param r NULL-terminated C-style string
|
||||
@return negative if l<r, 0 if l equals r, positive if l>r
|
||||
*/
|
||||
int alphanum_impl(const char *l, const char *r)
|
||||
{
|
||||
enum mode_t { STRING, NUMBER } mode=STRING;
|
||||
|
||||
while(*l && *r)
|
||||
{
|
||||
if(mode == STRING)
|
||||
{
|
||||
char l_char, r_char;
|
||||
while((l_char=*l) && (r_char=*r))
|
||||
{
|
||||
// check if this are digit characters
|
||||
const bool l_digit=alphanum_isdigit(l_char), r_digit=alphanum_isdigit(r_char);
|
||||
// if both characters are digits, we continue in NUMBER mode
|
||||
if(l_digit && r_digit)
|
||||
{
|
||||
mode=NUMBER;
|
||||
break;
|
||||
}
|
||||
// if only the left character is a digit, we have a result
|
||||
if(l_digit) return -1;
|
||||
// if only the right character is a digit, we have a result
|
||||
if(r_digit) return +1;
|
||||
// compute the difference of both characters
|
||||
const int diff=l_char - r_char;
|
||||
// if they differ we have a result
|
||||
if(diff != 0) return diff;
|
||||
// otherwise process the next characters
|
||||
++l;
|
||||
++r;
|
||||
}
|
||||
}
|
||||
else // mode==NUMBER
|
||||
{
|
||||
#ifdef ALPHANUM_LOCALE
|
||||
// get the left number
|
||||
char *end;
|
||||
unsigned long l_int=strtoul(l, &end, 0);
|
||||
l=end;
|
||||
|
||||
// get the right number
|
||||
unsigned long r_int=strtoul(r, &end, 0);
|
||||
r=end;
|
||||
#else
|
||||
// get the left number
|
||||
unsigned long l_int=0;
|
||||
while(*l && alphanum_isdigit(*l))
|
||||
{
|
||||
// TODO: this can overflow
|
||||
l_int=l_int*10 + *l-'0';
|
||||
++l;
|
||||
}
|
||||
|
||||
// get the right number
|
||||
unsigned long r_int=0;
|
||||
while(*r && alphanum_isdigit(*r))
|
||||
{
|
||||
// TODO: this can overflow
|
||||
r_int=r_int*10 + *r-'0';
|
||||
++r;
|
||||
}
|
||||
#endif
|
||||
|
||||
// if the difference is not equal to zero, we have a comparison result
|
||||
const long diff=l_int-r_int;
|
||||
if(diff != 0)
|
||||
return diff;
|
||||
|
||||
// otherwise we process the next substring in STRING mode
|
||||
mode=STRING;
|
||||
}
|
||||
}
|
||||
|
||||
if(*r) return -1;
|
||||
if(*l) return +1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Compare left and right with the same semantics as strcmp(), but with the
|
||||
"Alphanum Algorithm" which produces more human-friendly
|
||||
results. The classes lT and rT must implement "std::ostream
|
||||
operator<< (std::ostream&, const Ty&)".
|
||||
|
||||
@return negative if left<right, 0 if left==right, positive if left>right.
|
||||
*/
|
||||
template <typename lT, typename rT>
|
||||
int alphanum_comp(const lT& left, const rT& right)
|
||||
{
|
||||
#ifdef DOJDEBUG
|
||||
std::clog << "alphanum_comp<" << typeid(left).name() << "," << typeid(right).name() << "> " << left << "," << right << std::endl;
|
||||
#endif
|
||||
std::ostringstream l; l << left;
|
||||
std::ostringstream r; r << right;
|
||||
return alphanum_impl(l.str().c_str(), r.str().c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
Compare l and r with the same semantics as strcmp(), but with
|
||||
the "Alphanum Algorithm" which produces more human-friendly
|
||||
results.
|
||||
|
||||
@return negative if l<r, 0 if l==r, positive if l>r.
|
||||
*/
|
||||
template <>
|
||||
int alphanum_comp<std::string>(const std::string& l, const std::string& r)
|
||||
{
|
||||
#ifdef DOJDEBUG
|
||||
std::clog << "alphanum_comp<std::string,std::string> " << l << "," << r << std::endl;
|
||||
#endif
|
||||
return alphanum_impl(l.c_str(), r.c_str());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// now follow a lot of overloaded alphanum_comp() functions to get a
|
||||
// direct call to alphanum_impl() upon the various combinations of c
|
||||
// and c++ strings.
|
||||
|
||||
/**
|
||||
Compare l and r with the same semantics as strcmp(), but with
|
||||
the "Alphanum Algorithm" which produces more human-friendly
|
||||
results.
|
||||
|
||||
@return negative if l<r, 0 if l==r, positive if l>r.
|
||||
*/
|
||||
int alphanum_comp(char* l, char* r)
|
||||
{
|
||||
assert(l);
|
||||
assert(r);
|
||||
#ifdef DOJDEBUG
|
||||
std::clog << "alphanum_comp<char*,char*> " << l << "," << r << std::endl;
|
||||
#endif
|
||||
return alphanum_impl(l, r);
|
||||
}
|
||||
|
||||
int alphanum_comp(const char* l, const char* r)
|
||||
{
|
||||
assert(l);
|
||||
assert(r);
|
||||
#ifdef DOJDEBUG
|
||||
std::clog << "alphanum_comp<const char*,const char*> " << l << "," << r << std::endl;
|
||||
#endif
|
||||
return alphanum_impl(l, r);
|
||||
}
|
||||
|
||||
int alphanum_comp(char* l, const char* r)
|
||||
{
|
||||
assert(l);
|
||||
assert(r);
|
||||
#ifdef DOJDEBUG
|
||||
std::clog << "alphanum_comp<char*,const char*> " << l << "," << r << std::endl;
|
||||
#endif
|
||||
return alphanum_impl(l, r);
|
||||
}
|
||||
|
||||
int alphanum_comp(const char* l, char* r)
|
||||
{
|
||||
assert(l);
|
||||
assert(r);
|
||||
#ifdef DOJDEBUG
|
||||
std::clog << "alphanum_comp<const char*,char*> " << l << "," << r << std::endl;
|
||||
#endif
|
||||
return alphanum_impl(l, r);
|
||||
}
|
||||
|
||||
int alphanum_comp(const std::string& l, char* r)
|
||||
{
|
||||
assert(r);
|
||||
#ifdef DOJDEBUG
|
||||
std::clog << "alphanum_comp<std::string,char*> " << l << "," << r << std::endl;
|
||||
#endif
|
||||
return alphanum_impl(l.c_str(), r);
|
||||
}
|
||||
|
||||
int alphanum_comp(char* l, const std::string& r)
|
||||
{
|
||||
assert(l);
|
||||
#ifdef DOJDEBUG
|
||||
std::clog << "alphanum_comp<char*,std::string> " << l << "," << r << std::endl;
|
||||
#endif
|
||||
return alphanum_impl(l, r.c_str());
|
||||
}
|
||||
|
||||
int alphanum_comp(const std::string& l, const char* r)
|
||||
{
|
||||
assert(r);
|
||||
#ifdef DOJDEBUG
|
||||
std::clog << "alphanum_comp<std::string,const char*> " << l << "," << r << std::endl;
|
||||
#endif
|
||||
return alphanum_impl(l.c_str(), r);
|
||||
}
|
||||
|
||||
int alphanum_comp(const char* l, const std::string& r)
|
||||
{
|
||||
assert(l);
|
||||
#ifdef DOJDEBUG
|
||||
std::clog << "alphanum_comp<const char*,std::string> " << l << "," << r << std::endl;
|
||||
#endif
|
||||
return alphanum_impl(l, r.c_str());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
Functor class to compare two objects with the "Alphanum
|
||||
Algorithm". If the objects are no std::string, they must
|
||||
implement "std::ostream operator<< (std::ostream&, const Ty&)".
|
||||
*/
|
||||
template<class Ty>
|
||||
struct alphanum_less : public std::binary_function<Ty, Ty, bool>
|
||||
{
|
||||
bool operator()(const Ty& left, const Ty& right) const
|
||||
{
|
||||
return alphanum_comp(left, right) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#ifdef TESTMAIN
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
int main()
|
||||
{
|
||||
// testcases for the algorithm
|
||||
assert(doj::alphanum_comp("","") == 0);
|
||||
assert(doj::alphanum_comp("","a") < 0);
|
||||
assert(doj::alphanum_comp("a","") > 0);
|
||||
assert(doj::alphanum_comp("a","a") == 0);
|
||||
assert(doj::alphanum_comp("","9") < 0);
|
||||
assert(doj::alphanum_comp("9","") > 0);
|
||||
assert(doj::alphanum_comp("1","1") == 0);
|
||||
assert(doj::alphanum_comp("1","2") < 0);
|
||||
assert(doj::alphanum_comp("3","2") > 0);
|
||||
assert(doj::alphanum_comp("a1","a1") == 0);
|
||||
assert(doj::alphanum_comp("a1","a2") < 0);
|
||||
assert(doj::alphanum_comp("a2","a1") > 0);
|
||||
assert(doj::alphanum_comp("a1a2","a1a3") < 0);
|
||||
assert(doj::alphanum_comp("a1a2","a1a0") > 0);
|
||||
assert(doj::alphanum_comp("134","122") > 0);
|
||||
assert(doj::alphanum_comp("12a3","12a3") == 0);
|
||||
assert(doj::alphanum_comp("12a1","12a0") > 0);
|
||||
assert(doj::alphanum_comp("12a1","12a2") < 0);
|
||||
assert(doj::alphanum_comp("a","aa") < 0);
|
||||
assert(doj::alphanum_comp("aaa","aa") > 0);
|
||||
assert(doj::alphanum_comp("Alpha 2","Alpha 2") == 0);
|
||||
assert(doj::alphanum_comp("Alpha 2","Alpha 2A") < 0);
|
||||
assert(doj::alphanum_comp("Alpha 2 B","Alpha 2") > 0);
|
||||
|
||||
assert(doj::alphanum_comp(1,1) == 0);
|
||||
assert(doj::alphanum_comp(1,2) < 0);
|
||||
assert(doj::alphanum_comp(2,1) > 0);
|
||||
assert(doj::alphanum_comp(1.2,3.14) < 0);
|
||||
assert(doj::alphanum_comp(3.14,2.71) > 0);
|
||||
assert(doj::alphanum_comp(true,true) == 0);
|
||||
assert(doj::alphanum_comp(true,false) > 0);
|
||||
assert(doj::alphanum_comp(false,true) < 0);
|
||||
|
||||
std::string str("Alpha 2");
|
||||
assert(doj::alphanum_comp(str,"Alpha 2") == 0);
|
||||
assert(doj::alphanum_comp(str,"Alpha 2A") < 0);
|
||||
assert(doj::alphanum_comp("Alpha 2 B",str) > 0);
|
||||
|
||||
assert(doj::alphanum_comp(str,strdup("Alpha 2")) == 0);
|
||||
assert(doj::alphanum_comp(str,strdup("Alpha 2A")) < 0);
|
||||
assert(doj::alphanum_comp(strdup("Alpha 2 B"),str) > 0);
|
||||
|
||||
#if 1
|
||||
// show usage of the comparison functor with a set
|
||||
std::set<std::string, doj::alphanum_less<std::string> > s;
|
||||
s.insert("Xiph Xlater 58");
|
||||
s.insert("Xiph Xlater 5000");
|
||||
s.insert("Xiph Xlater 500");
|
||||
s.insert("Xiph Xlater 50");
|
||||
s.insert("Xiph Xlater 5");
|
||||
s.insert("Xiph Xlater 40");
|
||||
s.insert("Xiph Xlater 300");
|
||||
s.insert("Xiph Xlater 2000");
|
||||
s.insert("Xiph Xlater 10000");
|
||||
s.insert("QRS-62F Intrinsia Machine");
|
||||
s.insert("QRS-62 Intrinsia Machine");
|
||||
s.insert("QRS-60F Intrinsia Machine");
|
||||
s.insert("QRS-60 Intrinsia Machine");
|
||||
s.insert("Callisto Morphamax 7000 SE2");
|
||||
s.insert("Callisto Morphamax 7000 SE");
|
||||
s.insert("Callisto Morphamax 7000");
|
||||
s.insert("Callisto Morphamax 700");
|
||||
s.insert("Callisto Morphamax 600");
|
||||
s.insert("Callisto Morphamax 5000");
|
||||
s.insert("Callisto Morphamax 500");
|
||||
s.insert("Callisto Morphamax");
|
||||
s.insert("Alpha 2A-900");
|
||||
s.insert("Alpha 2A-8000");
|
||||
s.insert("Alpha 2A");
|
||||
s.insert("Alpha 200");
|
||||
s.insert("Alpha 2");
|
||||
s.insert("Alpha 100");
|
||||
s.insert("Allegia 60 Clasteron");
|
||||
s.insert("Allegia 52 Clasteron");
|
||||
s.insert("Allegia 51B Clasteron");
|
||||
s.insert("Allegia 51 Clasteron");
|
||||
s.insert("Allegia 500 Clasteron");
|
||||
s.insert("Allegia 50 Clasteron");
|
||||
s.insert("40X Radonius");
|
||||
s.insert("30X Radonius");
|
||||
s.insert("20X Radonius Prime");
|
||||
s.insert("20X Radonius");
|
||||
s.insert("200X Radonius");
|
||||
s.insert("10X Radonius");
|
||||
s.insert("1000X Radonius Maximus");
|
||||
// print sorted set to cout
|
||||
std::copy(s.begin(), s.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
|
||||
|
||||
// show usage of comparision functor with a map
|
||||
typedef std::map<std::string, int, doj::alphanum_less<std::string> > m_t;
|
||||
m_t m;
|
||||
m["z1.doc"]=1;
|
||||
m["z10.doc"]=2;
|
||||
m["z100.doc"]=3;
|
||||
m["z101.doc"]=4;
|
||||
m["z102.doc"]=5;
|
||||
m["z11.doc"]=6;
|
||||
m["z12.doc"]=7;
|
||||
m["z13.doc"]=8;
|
||||
m["z14.doc"]=9;
|
||||
m["z15.doc"]=10;
|
||||
m["z16.doc"]=11;
|
||||
m["z17.doc"]=12;
|
||||
m["z18.doc"]=13;
|
||||
m["z19.doc"]=14;
|
||||
m["z2.doc"]=15;
|
||||
m["z20.doc"]=16;
|
||||
m["z3.doc"]=17;
|
||||
m["z4.doc"]=18;
|
||||
m["z5.doc"]=19;
|
||||
m["z6.doc"]=20;
|
||||
m["z7.doc"]=21;
|
||||
m["z8.doc"]=22;
|
||||
m["z9.doc"]=23;
|
||||
// print sorted map to cout
|
||||
for(m_t::iterator i=m.begin(); i!=m.end(); ++i)
|
||||
std::cout << i->first << '\t' << i->second << std::endl;
|
||||
|
||||
// show usage of comparison functor with an STL algorithm on a vector
|
||||
std::vector<std::string> v;
|
||||
// vector contents are reversed sorted contents of the old set
|
||||
std::copy(s.rbegin(), s.rend(), std::back_inserter(v));
|
||||
// now sort the vector with the algorithm
|
||||
std::sort(v.begin(), v.end(), doj::alphanum_less<std::string>());
|
||||
// and print the vector to cout
|
||||
std::copy(v.begin(), v.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,111 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "antennatracker.h"
|
||||
|
||||
Antennatracker::Antennatracker() {
|
||||
antenna_id_map =
|
||||
std::make_shared<TrackerElementIntMap>();
|
||||
antenna_endp =
|
||||
std::make_shared<Kis_Net_Httpd_Simple_Tracked_Endpoint>("/antennas/antennas",
|
||||
antenna_id_map, &mutex);
|
||||
next_ant_id = 0;
|
||||
}
|
||||
|
||||
Antennatracker::~Antennatracker() {
|
||||
Globalreg::globalreg->RemoveGlobal("ANTENNATRACKER");
|
||||
}
|
||||
|
||||
int Antennatracker::add_antenna(uuid in_src, int in_srcnum, int in_adjustment) {
|
||||
local_locker l(&mutex);
|
||||
|
||||
for (auto ai : *antenna_id_map) {
|
||||
auto a = std::static_pointer_cast<tracked_antenna>(ai.second);
|
||||
|
||||
if (a->get_source_uuid() == in_src && a->get_source_antnum() == in_srcnum) {
|
||||
return a->get_id();
|
||||
}
|
||||
}
|
||||
|
||||
auto ant = std::make_shared<tracked_antenna>();
|
||||
|
||||
uuid u;
|
||||
u.GenerateRandomTimeUUID();
|
||||
|
||||
ant->set_id(next_ant_id++);
|
||||
ant->set_source_uuid(in_src);
|
||||
ant->set_source_antnum(in_srcnum);
|
||||
ant->set_power_adjust(in_adjustment);
|
||||
|
||||
ant->set_antenna_uuid(u);
|
||||
|
||||
antenna_id_map->insert(ant->get_id(), ant);
|
||||
|
||||
return ant->get_id();
|
||||
}
|
||||
|
||||
int Antennatracker::add_antenna(uuid in_src, int in_srcnum, int in_adjustment, uuid in_ant_uuid) {
|
||||
local_locker l(&mutex);
|
||||
|
||||
for (auto ai : *antenna_id_map) {
|
||||
auto a = std::static_pointer_cast<tracked_antenna>(ai.second);
|
||||
|
||||
if (a->get_source_uuid() == in_src && a->get_source_antnum() == in_srcnum) {
|
||||
return a->get_id();
|
||||
}
|
||||
}
|
||||
|
||||
auto ant = std::make_shared<tracked_antenna>();
|
||||
|
||||
ant->set_id(next_ant_id++);
|
||||
ant->set_source_uuid(in_src);
|
||||
ant->set_source_antnum(in_srcnum);
|
||||
ant->set_power_adjust(in_adjustment);
|
||||
ant->set_antenna_uuid(in_ant_uuid);
|
||||
|
||||
antenna_id_map->insert(ant->get_id(), ant);
|
||||
|
||||
return ant->get_id();
|
||||
}
|
||||
|
||||
int Antennatracker::set_antenna_adjustment(int in_antnum, int in_adjustment) {
|
||||
local_locker l(&mutex);
|
||||
|
||||
auto ai = antenna_id_map->find(in_antnum);
|
||||
|
||||
if (ai == antenna_id_map->end())
|
||||
return -1;
|
||||
|
||||
auto a = std::static_pointer_cast<tracked_antenna>(ai->second);
|
||||
a->set_power_adjust(in_adjustment);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::shared_ptr<tracked_antenna> Antennatracker::get_antenna(int in_antnum) {
|
||||
local_locker l(&mutex);
|
||||
|
||||
auto ai = antenna_id_map->find(in_antnum);
|
||||
|
||||
if (ai == antenna_id_map->end())
|
||||
return nullptr;
|
||||
|
||||
return std::static_pointer_cast<tracked_antenna>(ai->second);
|
||||
}
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __ANTENNATRACKER_H__
|
||||
#define __ANTENNATRACKER_H__
|
||||
|
||||
#include "config.h"
|
||||
#include "kis_net_microhttpd.h"
|
||||
#include "globalregistry.h"
|
||||
#include "trackedcomponent.h"
|
||||
#include "kis_mutex.h"
|
||||
|
||||
/* Antenna tracker
|
||||
*
|
||||
* Map per-source antennas to a common antenna ID number for fast grouping across sources.
|
||||
*
|
||||
* Sources should register antennas with the antenna mapping system and use those simple
|
||||
* IDs for mapping to per-antenna signals.
|
||||
*
|
||||
* Other mechanisms, such as SDOA, can use these groupings for fast analysis
|
||||
*/
|
||||
|
||||
class tracked_antenna : public tracker_component {
|
||||
public:
|
||||
tracked_antenna() :
|
||||
tracker_component(0) {
|
||||
register_fields();
|
||||
reserve_fields(NULL);
|
||||
}
|
||||
|
||||
tracked_antenna(int in_id) :
|
||||
tracker_component(in_id) {
|
||||
register_fields();
|
||||
reserve_fields(NULL);
|
||||
}
|
||||
|
||||
tracked_antenna(int in_id, std::shared_ptr<TrackerElementMap> e) :
|
||||
tracker_component(in_id) {
|
||||
register_fields();
|
||||
reserve_fields(e);
|
||||
}
|
||||
|
||||
virtual uint32_t get_signature() const override {
|
||||
return Adler32Checksum("tracked_antenna");
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<TrackerElement> clone_type() override {
|
||||
using this_t = std::remove_pointer<decltype(this)>::type;
|
||||
auto dup = std::unique_ptr<this_t>(new this_t());
|
||||
return std::move(dup);
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<TrackerElement> clone_type(int in_id) override {
|
||||
using this_t = std::remove_pointer<decltype(this)>::type;
|
||||
auto dup = std::unique_ptr<this_t>(new this_t(in_id));
|
||||
return std::move(dup);
|
||||
}
|
||||
|
||||
__Proxy(antenna_id, uint32_t, unsigned int, unsigned int, antenna_id);
|
||||
__Proxy(antenna_uuid, uuid, uuid, uuid, antenna_uuid);
|
||||
__Proxy(source_uuid, uuid, uuid, uuid, source_uuid);
|
||||
__Proxy(source_antnum, int32_t, int32_t, int32_t, source_antnum);
|
||||
__Proxy(power_adjust, int32_t, int32_t, int32_t, power_adjust);
|
||||
|
||||
protected:
|
||||
virtual void register_fields() override {
|
||||
tracker_component::register_fields();
|
||||
|
||||
RegisterField("kismet.antenna.id", "Antenna ID for fast lookup", &antenna_id);
|
||||
RegisterField("kismet.antenna.uuid", "Antenna UUID", &antenna_uuid);
|
||||
RegisterField("kismet.antenna.source_uuid", "UUID of antenna source", &source_uuid);
|
||||
RegisterField("kismet.antenna.source_antnum", "Antenna number on source", &source_antnum);
|
||||
RegisterField("kismet.antenna.power_adjust", "Optional power adjustment", &power_adjust);
|
||||
}
|
||||
|
||||
std::shared_ptr<TrackerElementInt32> antenna_id;
|
||||
std::shared_ptr<TrackerElementUUID> antenna_uuid;
|
||||
std::shared_ptr<TrackerElementUUID> source_uuid;
|
||||
std::shared_ptr<TrackerElementInt32> power_adjust;
|
||||
std::shared_ptr<TrackerElementInt32> source_antnum;
|
||||
|
||||
};
|
||||
|
||||
class Antennatracker : public LifetimeGlobal {
|
||||
public:
|
||||
static std::shared_ptr<Antennatracker> create_at() {
|
||||
auto mon = std::make_shared<Antennatracker>();
|
||||
Globalreg::globalreg->RegisterLifetimeGlobal(mon);
|
||||
Globalreg::globalreg->InsertGlobal("ANTENNATRACKER", mon);
|
||||
|
||||
return mon;
|
||||
}
|
||||
|
||||
Antennatracker();
|
||||
virtual ~Antennatracker();
|
||||
|
||||
// Add a new antenna
|
||||
int add_antenna(uuid in_src, int in_srcnum, int adjustment);
|
||||
int add_antenna(uuid in_src, int in_srcnum, int adjustment, uuid in_ant_uuid);
|
||||
|
||||
// Adjust an existing antenna
|
||||
int set_antenna_adjustment(int in_antnum, int adjustment);
|
||||
|
||||
// Retreive antenna
|
||||
std::shared_ptr<tracked_antenna> get_antenna(int in_antnum);
|
||||
|
||||
protected:
|
||||
kis_recursive_timed_mutex mutex;
|
||||
|
||||
int next_ant_id;
|
||||
|
||||
std::shared_ptr<TrackerElementIntMap> antenna_id_map;
|
||||
|
||||
std::shared_ptr<Kis_Net_Httpd_Simple_Tracked_Endpoint> antenna_endp;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,434 +0,0 @@
|
|||
/* From MacStumbler, which is under GPL */
|
||||
|
||||
/*
|
||||
* Apple80211.h
|
||||
*
|
||||
* This is the reverse engineered header for the Apple80211 private framework.
|
||||
* The framework can be found at /System/Library/PrivateFrameworks/Apple80211.framework.
|
||||
* Linking with Apple80211.framework requires CoreFoundation.framework and AppKit.framework.
|
||||
*
|
||||
* Note that there is also information in the IORegistry, see
|
||||
* ioreg -c AirPortDriver -w 0
|
||||
*
|
||||
* Contributors:
|
||||
* korben - korben@cox.net
|
||||
* jason - catalyst@mac.com
|
||||
* ragge - ragge@nada.kth.se
|
||||
*
|
||||
* Last updated by korben on 5/15/2002
|
||||
*/
|
||||
|
||||
/* ChangeLog:
|
||||
|
||||
2002-05-14 ragge
|
||||
Changed argument types and count to procedures
|
||||
Added WirelessScan
|
||||
Changed name of unknown field to beaconInterval
|
||||
Added error values and error return types
|
||||
|
||||
2002-05-15 korben
|
||||
Combined ragge's changes with jason's
|
||||
|
||||
2002-05-17 korben
|
||||
fixed adhoc and mangaged WINetworkInfoFlags per ragge's request
|
||||
Added WirelessEncrypt and WirelessKey declarations
|
||||
Updated WirelessJoinWEP and WirelessMakeIBSS comments regarding keys
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __APPLE_80211__
|
||||
#define __APPLE_80211__
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
/*
|
||||
A WirelessContext should be created using WirelessAttach
|
||||
before any other Wireless functions are called. WirelessDetach
|
||||
is used to dispose of a WirelessContext.
|
||||
*/
|
||||
typedef struct __WirelessContext *WirelessContextPtr;
|
||||
|
||||
struct WirelessInfo
|
||||
{
|
||||
UInt16 link_qual; /* Link quality, percent? */
|
||||
UInt16 comms_qual; /* Communication Quality */
|
||||
UInt16 signal; /* Signal level */
|
||||
UInt16 noise; /* Noise level */
|
||||
UInt16 port_stat; /* HERMES_RID_PORTSTAT? (Uncertain about the meaning of this! 1=off? 2=connetion bad? 3=AdHoc Create? 4=BSS (Client)? 5=BSS+OutOfRange?) */
|
||||
UInt16 client_mode; /* 1 = BSS, 4 = Create IBSS */
|
||||
UInt16 u7; /* ? */
|
||||
UInt16 power; /* Power on flag */
|
||||
UInt16 u9; /* 0=bad?, 1=ok?, 2=wrong key? */
|
||||
UInt8 macAddress[6]; /* MAC address of wireless access point. */
|
||||
SInt8 name[34]; /* Name of current (or wanted?) network. */
|
||||
};
|
||||
typedef struct WirelessInfo WirelessInfo;
|
||||
/*
|
||||
I'm not sure what most of the values in the WirelessInfo structure
|
||||
are for, but here are some examples of the numbers returned:
|
||||
|
||||
With Airport Off:
|
||||
0 0 0 0 1 1 0 0 1
|
||||
|
||||
With Airport On:
|
||||
72 22 31 9 4 1 0 1 1
|
||||
|
||||
With Computer to Computer Network:
|
||||
0 0 0 0 3 4 0 1 1
|
||||
|
||||
- jason
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
WINetworkInfoFlags are used in the WirelessNetworkInfo struct
|
||||
returned by the WirelessScanSplit function.
|
||||
|
||||
I have seen other flags, but I don't know what they stand for. - korben
|
||||
|
||||
I think these should probably be bit masks, but I am using what
|
||||
korben figured out. - jason
|
||||
*/
|
||||
typedef UInt16 WINetworkInfoFlags;
|
||||
enum
|
||||
{
|
||||
kWINetworkManagedFlag = 0x0001,
|
||||
kWINetworkAdhocFlag = 0x0002,
|
||||
kWINetworkEncryptedFlag = 0x0010
|
||||
};
|
||||
|
||||
typedef SInt32 WIErr;
|
||||
enum {
|
||||
airpParamErr = -2013261823, /* 0x88001001 */
|
||||
airpNoIOServiceErr = -2013261822, /* 0x88001002 */
|
||||
airpInternalErr = -2013261821, /* 0x88001003 */
|
||||
airpUnk4Err = -2013261820, /* 0x88001004 */
|
||||
airpOutOfMemErr = -2013261819, /* 0x88001005 */
|
||||
airpInternal2Err = -2013261818, /* 0x88001006 */
|
||||
airpUnk7Err = -2013261817, /* 0x88001007 */
|
||||
airpUnk8Err = -2013261816, /* 0x88001008 */
|
||||
airpUnk9Err = -2013261815, /* 0x88001009 */
|
||||
airpUnkaErr = -2013261814, /* 0x8800100a */
|
||||
airpNoPowerErr = -2013261813 /* 0x8800100b */
|
||||
};
|
||||
/* The meaning of these error codes can be wrong, and the list is not
|
||||
* complete. In general checking for noErr (0) should be enough */
|
||||
|
||||
struct WirelessNetworkInfo
|
||||
{
|
||||
UInt16 channel; /* Channel for the network. */
|
||||
UInt16 noise; /* Noise for the network. 0 for Adhoc. */
|
||||
UInt16 signal; /* Signal strength of the network. 0 for Adhoc. */
|
||||
UInt8 macAddress[6]; /* MAC address of the wireless access point. */
|
||||
UInt16 beaconInterval; /* beacon interval in milliseconds */
|
||||
WINetworkInfoFlags flags; /* Flags for the network. */
|
||||
UInt16 nameLen;
|
||||
SInt8 name[32];
|
||||
};
|
||||
typedef struct WirelessNetworkInfo WirelessNetworkInfo;
|
||||
|
||||
typedef UInt8 WirelessKey[13]; // For use with WirelessEncrypt
|
||||
|
||||
|
||||
/*
|
||||
* WirelessIsAvailable()
|
||||
*
|
||||
* Returns 1 if a wireless interface is available, 0 otherwise
|
||||
*/
|
||||
extern int WirelessIsAvailable(void);
|
||||
|
||||
/*
|
||||
* WirelessAttach()
|
||||
*
|
||||
* WirelessAttach should be called before all other Wireless functions.
|
||||
*
|
||||
* outContext returns the contextPtr you will pass
|
||||
* to all other Wireless functions
|
||||
* The second argument must be zero.
|
||||
*/
|
||||
extern WIErr WirelessAttach(
|
||||
WirelessContextPtr *outContext,
|
||||
const UInt32);
|
||||
|
||||
/*
|
||||
* WirelessDetach()
|
||||
*
|
||||
* WirelessDetach is called after you are done calling Wireless functions.
|
||||
* It will free all memory being used by the library.
|
||||
*
|
||||
* inContext is the contextPtr you want to dispose of.
|
||||
*/
|
||||
extern WIErr WirelessDetach(
|
||||
WirelessContextPtr inContext);
|
||||
|
||||
/*
|
||||
* WirelessGetPower()
|
||||
*
|
||||
* WirelessGetPower returns the power state of Airport.
|
||||
*
|
||||
* inContext is the contextPtr created by WirelessAttach.
|
||||
* outPower is 0 for off and 1 for on.
|
||||
*/
|
||||
extern WIErr WirelessGetPower(
|
||||
WirelessContextPtr inContext,
|
||||
UInt8 *outPower);
|
||||
|
||||
/*
|
||||
* WirelessSetPower()
|
||||
*
|
||||
* WirelessSetPower will turn Airport on or off.
|
||||
*
|
||||
* inContext is the contextPtr created by WirelessAttach.
|
||||
* inPower is 0 for off and 1 for on.
|
||||
*/
|
||||
extern WIErr WirelessSetPower(
|
||||
WirelessContextPtr inContext,
|
||||
UInt8 inPower);
|
||||
|
||||
/*
|
||||
* WirelessGetEnabled()
|
||||
*
|
||||
* WirelessGetEnabled could have returned the Enabled state of Airport,
|
||||
* but it seems to rather return the Power state.
|
||||
*
|
||||
* inContext is the contextPtr created by WirelessAttach.
|
||||
* outEnabled is 0 for off and 1 for on.
|
||||
*/
|
||||
extern WIErr WirelessGetEnabled(
|
||||
WirelessContextPtr inContext,
|
||||
UInt8 *outEnabled);
|
||||
|
||||
/*
|
||||
* WirelessSetEnabled()
|
||||
*
|
||||
* WirelessSetEnabled will enable or disable Airport communication.
|
||||
*
|
||||
* inContext is the contextPtr created by WirelessAttach.
|
||||
* inEnabled is 0 for off and 1 for on.
|
||||
*/
|
||||
extern WIErr WirelessSetEnabled(
|
||||
WirelessContextPtr inContext,
|
||||
UInt32 inEnabled);
|
||||
|
||||
/*
|
||||
* WirelessGetInfo()
|
||||
*
|
||||
* WirelessGetInfo returns info about the state
|
||||
* of the current wireless connection.
|
||||
*
|
||||
* inContext is the contextPtr created by WirelessAttach.
|
||||
* outInfo is a WirelessInfo structure containing state info.
|
||||
*/
|
||||
extern WIErr WirelessGetInfo(
|
||||
WirelessContextPtr inContext,
|
||||
WirelessInfo *outInfo);
|
||||
|
||||
/*
|
||||
* WirelessScanSplit(), WirelessScan()
|
||||
*
|
||||
* WirelessScanSplit scans for available wireless networks.
|
||||
* It will allocate 2 CFArrays to store a list
|
||||
* of managed and adhoc networks. The arrays hold CFData
|
||||
* objects which contain WirelessNetworkInfo structures.
|
||||
* Note: An adhoc network created on the computer the
|
||||
* scan is running on will not be found. WirelessGetInfo
|
||||
* can be used to find info about a local adhoc network.
|
||||
*
|
||||
* inContext is the contextPtr created by WirelessAttach.
|
||||
* apList will contain a CFArrayRef of managed networks.
|
||||
* adhocList will contain a CFArrayRef of adhoc networks.
|
||||
* For example:
|
||||
* WirelessScanSplit(clientContext, &apList, &adhocList, 1)
|
||||
*
|
||||
* If stripDups != 0 only one basestation for each SSID will be returned
|
||||
*
|
||||
* WirelessScan works the same way but does not split the list by AP type
|
||||
*/
|
||||
extern WIErr WirelessScanSplit(
|
||||
WirelessContextPtr inContext,
|
||||
CFArrayRef *apList,
|
||||
CFArrayRef *adhocList,
|
||||
const UInt32 stripDups);
|
||||
|
||||
extern WIErr WirelessScan(
|
||||
WirelessContextPtr inContext,
|
||||
CFArrayRef *apList,
|
||||
const UInt32 stripDups);
|
||||
|
||||
/*
|
||||
* WirelessJoin()
|
||||
*
|
||||
* WirelessJoin is used to join a Wireless network.
|
||||
*
|
||||
* inContext is the contextPtr created by WirelessAttach.
|
||||
* inNetworkName is the name of the network to join.
|
||||
*/
|
||||
extern WIErr WirelessJoin(
|
||||
WirelessContextPtr inContext,
|
||||
CFStringRef inNetworkName);
|
||||
|
||||
/*
|
||||
* WirelessJoinWEP()
|
||||
*
|
||||
* WirelessJoinWEP is used to join an encrypted network.
|
||||
*
|
||||
* inContext is the contextPtr created by WirelessAttach.
|
||||
* inNetworkName is the name of the network to join.
|
||||
* inNetworkPassword is the password/key of the network.
|
||||
*
|
||||
* inNetworkPassword description:
|
||||
* - Passwords are just a string of any length, they will be hashed into a key.
|
||||
* - Keys should be passed as a hex string, optionally beginning with 0x,
|
||||
* and must be either 10 digits for a 40bit key or 26 digits for a 104bit key,
|
||||
* or an ascii/binary representation of the key, 5 or 13 bytes long.
|
||||
* - It can also be the empty string, meaning no encryption.
|
||||
*
|
||||
* For more info see:
|
||||
* http://kbase.info.apple.com/cgi-bin/WebObjects/kbase.woa/11/wa/query?searchMode=Expert&type=id&val=KC.106424
|
||||
*/
|
||||
extern WIErr WirelessJoinWEP(
|
||||
WirelessContextPtr inContext,
|
||||
CFStringRef inNetworkName,
|
||||
CFStringRef inNetworkPassword);
|
||||
|
||||
/*
|
||||
* WirelessEncrypt
|
||||
*
|
||||
* WirelessEncrypt is called from WirelessJoinWEP and
|
||||
* WirelessMakeIBSS to translate a string into a 40 or
|
||||
* 104-bit Apple hashed WEP key.
|
||||
* Third argument is 0 for 40 bit key and 1 for 104 bit key.
|
||||
*
|
||||
* Sample usage:
|
||||
*
|
||||
* WirelessKey myKey;
|
||||
* WirelessEncrypt(@"password", &myKey, 1);
|
||||
* for(int i=0; i <= 12; i++)
|
||||
* printf("%.2X ", myKey[i]);
|
||||
*
|
||||
*/
|
||||
extern WIErr WirelessEncrypt(
|
||||
CFStringRef inNetworkPassword,
|
||||
WirelessKey *wepKey,
|
||||
const UInt32 use104bits);
|
||||
|
||||
/*
|
||||
* WirelessGetChannels()
|
||||
*
|
||||
* WirelessGetChannels is used to get valid channels for
|
||||
* creating an adhoc network.
|
||||
*
|
||||
* inContext is the contextPtr created by WirelessAttach.
|
||||
* outChannelBitField contains a bit field of valid channels.
|
||||
* For example if 0x07FF is returned then bits 0 through 10
|
||||
* are set, which means channels 1 through 11 are valid.
|
||||
*/
|
||||
extern WIErr WirelessGetChannels(
|
||||
WirelessContextPtr inContext,
|
||||
UInt16 *outChannelBitField);
|
||||
|
||||
/*
|
||||
* WirelessGetBestChannel()
|
||||
*
|
||||
* WirelessGetBestChannel is used to get the best channel
|
||||
* for creating an adhoc network on.
|
||||
*
|
||||
* inContext is the contextPtr created by WirelessAttach.
|
||||
* outBestChannel is the best channel for a wireless network.
|
||||
*/
|
||||
extern WIErr WirelessGetBestChannel(
|
||||
WirelessContextPtr inContext,
|
||||
UInt16 *outBestChannel);
|
||||
|
||||
/*
|
||||
* WirelessMakeIBSS()
|
||||
*
|
||||
* WirelessMakeIBSS is used to create a computer to computer
|
||||
* adhoc wireless network.
|
||||
*
|
||||
* inContext is the contextPtr created by WirelessAttach.
|
||||
* inNetworkName is the name of the network to create.
|
||||
* inNetworkPassword is the password/key for the new network.
|
||||
* inChannel is the wireless channel the network will use.
|
||||
*
|
||||
* inNetworkPassword description:
|
||||
* - Passwords are just a string of any length, they will be hashed into a key.
|
||||
* - Keys should be passed as a hex string, optionally beginning with 0x,
|
||||
* and must be either 10 digits for a 40bit key or 26 digits for a 104bit key.
|
||||
* - It can also be the empty string, meaning no encryption.
|
||||
*
|
||||
* For more info see:
|
||||
* http://kbase.info.apple.com/cgi-bin/WebObjects/kbase.woa/11/wa/query?searchMode=Expert&type=id&val=KC.106424
|
||||
*/
|
||||
extern WIErr WirelessMakeIBSS(
|
||||
WirelessContextPtr inContex,
|
||||
CFStringRef inNetworkName,
|
||||
CFStringRef inNetworkPassword,
|
||||
UInt32 inChannel);
|
||||
|
||||
/*
|
||||
* Get information from the Hermes chip.
|
||||
*
|
||||
* RIDno is the Hermes RID number for the data to get, as
|
||||
* 0xFC01 - HERMES_RID_CNFOWNMACADDR
|
||||
* 0xFC02 - HERMES_RID_CNFDESIREDSSID
|
||||
* 0xFDC1 - HERMES_RID_CURRENTCHANNEL
|
||||
* and so on.
|
||||
* Don't know why, but 0xF100 - HERMES_INQ_TALLIES works here too,
|
||||
* and a struct with the counters will be returned. (The data
|
||||
* returned seems to be lagging, though, call twice for fresh data.)
|
||||
*/
|
||||
extern WIErr WirelessHCF_GetInfo(
|
||||
WirelessContextPtr inContext,
|
||||
UInt16 RIDno,
|
||||
UInt32 outBufSize,
|
||||
void *outBuf);
|
||||
|
||||
|
||||
/*
|
||||
***** MISSING FUNCTIONS *****
|
||||
|
||||
These functions are used to configure an Access Point (Base Station).
|
||||
Most of these are used by the Airport Admin Utility.app, and some like
|
||||
WirelessAP_GetStatus are even used by Internet Connect.app. - jason
|
||||
|
||||
WirelessAP_BinaryCurrentVersion
|
||||
WirelessAP_BinaryCurrentVersion2
|
||||
WirelessAP_BinaryIsCurrent
|
||||
WirelessAP_BinaryUpload
|
||||
WirelessAP_BinaryUploadACP
|
||||
WirelessAP_BinaryVersion
|
||||
WirelessAP_Dial
|
||||
WirelessAP_DialDynamic
|
||||
WirelessAP_Explore
|
||||
WirelessAP_ForceIPAddress
|
||||
WirelessAP_GetBridgeStatus
|
||||
WirelessAP_GetCommonVariables
|
||||
WirelessAP_GetCommonVariablesACP
|
||||
WirelessAP_GetFullStatus
|
||||
WirelessAP_GetModemVersion
|
||||
WirelessAP_GetModemVersionACP
|
||||
WirelessAP_GetStatus
|
||||
WirelessAP_GetType
|
||||
WirelessAP_GetVersion
|
||||
WirelessAP_Hangup
|
||||
WirelessAP_IsConnected
|
||||
WirelessAP_Read
|
||||
WirelessAP_ReadACP
|
||||
WirelessAP_ResetNVRAM
|
||||
WirelessAP_Restart
|
||||
WirelessAP_RestartACP
|
||||
WirelessAP_Write
|
||||
WirelessAP_WriteACP
|
||||
|
||||
I can't find any apps that use these functions. - jason
|
||||
|
||||
WirelessAccessPoint
|
||||
WirelessConfigure
|
||||
WirelessDownloadFW
|
||||
WirelessSetKey
|
||||
*/
|
||||
|
||||
extern WIErr WirelessPrivate(WirelessContextPtr inContext,void* in_ptr,int in_bytes,void* out_ptr,int out_bytes);
|
||||
|
||||
#endif // __APPLE_80211__
|
File diff suppressed because it is too large
Load Diff
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
// Minimal wrapper around libbackward from
|
||||
// https://github.com/bombela/backward-cpp
|
||||
|
||||
#ifndef __BACKWARD_WRAPPER_H__
|
||||
#define __BACKWARD_WRAPPER_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef DISABLE_BACKWARD
|
||||
#include "backward.h"
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "base64.h"
|
||||
|
||||
const char Base64::b64_values[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
void Base64::decodeblock(unsigned char *in, unsigned char *out) {
|
||||
out[0] = in[0] << 2 | in[1] >> 4;
|
||||
out[1] = in[1] << 4 | in[2] >> 2;
|
||||
out[2] = in[2] << 6 | in[3] >> 0;
|
||||
out[3] = 0;
|
||||
}
|
||||
|
||||
std::string Base64::decode(std::string in_str) {
|
||||
std::string out;
|
||||
unsigned char obuf[4], ibuf[4];
|
||||
int phase, c;
|
||||
unsigned int i;
|
||||
char *pos;
|
||||
|
||||
memset(obuf, 0, 4);
|
||||
memset(ibuf, 0, 4);
|
||||
|
||||
// Make a rough guess at the decoded length to optimise sizing
|
||||
out.reserve(in_str.length() * 0.75);
|
||||
|
||||
phase = 0;
|
||||
|
||||
for (i = 0; i < in_str.length(); i++) {
|
||||
c = in_str[i];
|
||||
|
||||
if (c == '=') {
|
||||
decodeblock(ibuf, obuf);
|
||||
out.append((char *) obuf, phase);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Find the binary # this digit corresponds to
|
||||
pos = strchr((char *) b64_values, c);
|
||||
|
||||
// Fail on invalid characters
|
||||
if (pos == NULL) {
|
||||
return out;
|
||||
}
|
||||
|
||||
// Get the integer position in the table
|
||||
ibuf[phase] = pos - b64_values;
|
||||
|
||||
phase = (phase + 1) % 4;
|
||||
|
||||
// 4 characters read?
|
||||
if (phase == 0) {
|
||||
decodeblock(ibuf, obuf);
|
||||
out.append((char *) obuf, 3);
|
||||
memset(ibuf, 0, 4);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sstream>
|
||||
|
||||
#ifndef __BASE64_H__
|
||||
#define __BASE64_H__
|
||||
|
||||
/* Unexciting base64 implementation
|
||||
* Needed to handle b64 encoded post data for the webserver
|
||||
*/
|
||||
|
||||
class Base64 {
|
||||
public:
|
||||
/* Decode a string; return raw data if it was valid */
|
||||
static std::string decode(std::string in_str);
|
||||
|
||||
// Convert 4 6-bit b64 characters into 3 8-bit standard bytes.
|
||||
// In and out must be able to hold the appropriate amount of data.
|
||||
static void decodeblock(unsigned char *in, unsigned char *out);
|
||||
|
||||
protected:
|
||||
const static char b64_values[];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,615 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#ifdef SYS_LINUX
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(SYS_OPENBSD) && defined(HAVE_MACHINE_APMVAR_H)
|
||||
#include <machine/apmvar.h>
|
||||
#endif
|
||||
|
||||
#ifdef SYS_DARWIN
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <IOKit/ps/IOPowerSources.h>
|
||||
#include <IOKit/ps/IOPSKeys.h>
|
||||
|
||||
#define LCDP_BATT_ABSENT 1
|
||||
#define LCDP_AC_ON 2
|
||||
#define LCDP_BATT_UNKNOWN 3
|
||||
#define LCDP_AC_OFF 4
|
||||
#define LCDP_BATT_CHARGING 5
|
||||
#define LCDP_BATT_HIGH 6
|
||||
#define LCDP_BATT_LOW 7
|
||||
#define LCDP_BATT_CRITICAL 8
|
||||
#endif
|
||||
|
||||
#ifdef SYS_NETBSD
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/envsys.h>
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
#endif
|
||||
|
||||
#include "battery.h"
|
||||
|
||||
int Fetch_Battery_Linux_ACPI(kis_battery_info *out __attribute__((unused))) {
|
||||
#ifdef SYS_LINUX
|
||||
char buf[128];
|
||||
FILE *bfile;
|
||||
|
||||
DIR *adir;
|
||||
struct dirent *ent;
|
||||
int rate = 0, cap = 0, remain = 0, tint = 0;
|
||||
std::string bpath;
|
||||
|
||||
adir = opendir("/proc/acpi/battery");
|
||||
|
||||
if (adir == NULL) {
|
||||
// No batteries, assume we're on AC
|
||||
out->percentage = 0;
|
||||
out->charging = 0;
|
||||
out->remaining_sec = 0;
|
||||
out->ac = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((ent = readdir(adir)) != NULL) {
|
||||
bpath = "/proc/acpi/battery/" + std::string(ent->d_name) + "/state";
|
||||
|
||||
if ((bfile = fopen(bpath.c_str(), "r")) == NULL)
|
||||
continue;
|
||||
while (fgets(buf, 128, bfile)) {
|
||||
if (strlen(buf) < 26)
|
||||
continue;
|
||||
|
||||
if (strstr(buf, "charging state:") == buf) {
|
||||
// Only reset charging if no batteries are charging
|
||||
if (strstr(buf + 25, "charged") == (buf + 25) && out->charging != 1) {
|
||||
out->charging = 2;
|
||||
} else if (strstr(buf + 25, "discharging") == (buf + 25)) {
|
||||
out->charging = 0;
|
||||
out->ac = 0;
|
||||
} else if (strstr(buf + 25, "charging") == (buf + 25)) {
|
||||
out->charging = 1;
|
||||
out->ac = 1;
|
||||
}
|
||||
} else if (strstr(buf, "present rate:") == buf) {
|
||||
// Add discharge rates across all batteries
|
||||
if (sscanf(buf + 25, "%d", &tint) == 1) {
|
||||
rate += tint;
|
||||
}
|
||||
} else if (strstr(buf, "remaining capacity:") == buf) {
|
||||
// Add remaining across all batteries
|
||||
if (sscanf(buf + 25, "%d", &tint) == 1)
|
||||
remain += tint;
|
||||
}
|
||||
}
|
||||
fclose(bfile);
|
||||
|
||||
bpath = "/proc/acpi/battery/" + std::string(ent->d_name) + "/info";
|
||||
if ((bfile = fopen(bpath.c_str(), "r")) == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while (fgets(buf, 128, bfile)) {
|
||||
if (strlen(buf) < 26)
|
||||
continue;
|
||||
|
||||
// Add the last fulls
|
||||
if (strstr(buf, "last full capacity:") == buf) {
|
||||
if (sscanf(buf + 25, "%d", &tint) == 1) {
|
||||
cap += tint;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(bfile);
|
||||
}
|
||||
|
||||
closedir(adir);
|
||||
|
||||
out->percentage = (float) ((float) remain / cap) * 100;
|
||||
|
||||
if (rate > 0)
|
||||
out->remaining_sec = (float) ((float) remain / rate) * 60 * 60;
|
||||
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Fetch_Battery_Linux_Sys(kis_battery_info *out __attribute__((unused))) {
|
||||
/* sys battery handling strongly derived from the ACPI code by
|
||||
*
|
||||
* Grahame Bowland <grahame@angrygoats.net>
|
||||
* and
|
||||
* Michael Meskes <meskes@debian.org>
|
||||
*/
|
||||
#ifdef SYS_LINUX
|
||||
// Default to being on AC; if we lack battery info we're probably
|
||||
// not a laptop
|
||||
out->ac = 1;
|
||||
|
||||
FILE *f;
|
||||
struct stat statbuf;
|
||||
|
||||
const char *base_dir = "/sys/class/power_supply/";
|
||||
char bdir[128];
|
||||
char fpath[128];
|
||||
|
||||
char *line;
|
||||
size_t linesz;
|
||||
|
||||
int itr;
|
||||
|
||||
int on_ac = 0;
|
||||
int charging = 0;
|
||||
|
||||
struct _long_file_pairs {
|
||||
const char *filename;
|
||||
long *target;
|
||||
};
|
||||
|
||||
long power_now;
|
||||
long current_now;
|
||||
long charge_now;
|
||||
long energy_now;
|
||||
long voltage_now;
|
||||
long charge_full;
|
||||
long energy_full;
|
||||
|
||||
long present_rate = -1;
|
||||
long remaining_capacity = -1;
|
||||
long remaining_energy = -1;
|
||||
long last_capacity = -1;
|
||||
long last_capacity_unit = -1;
|
||||
long voltage = -1;
|
||||
long seconds_remaining = -1;
|
||||
|
||||
int percentage = 0;
|
||||
|
||||
struct _long_file_pairs filepairs[] = {
|
||||
{ "power_now", &power_now },
|
||||
{ "current_now", ¤t_now },
|
||||
{ "charge_now", &charge_now },
|
||||
{ "energy_now", &energy_now },
|
||||
{ "voltage_now", &voltage_now },
|
||||
{ "charge_full", &charge_full },
|
||||
{ "energy_full", &energy_full },
|
||||
{ "end", NULL }
|
||||
};
|
||||
|
||||
// Are we indexed as bat0 or bat1
|
||||
snprintf(bdir, 128, "%s/BAT0", base_dir);
|
||||
if (stat(bdir, &statbuf) < 0) {
|
||||
snprintf(bdir, 128, "%s/BAT1", base_dir);
|
||||
if (stat(bdir, &statbuf) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(fpath, 128, "%s/status", bdir);
|
||||
if ((f = fopen(fpath, "r")) == NULL) {
|
||||
printf("Couldn't open %s\n", fpath);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t glsz __attribute__((unused));
|
||||
line = NULL;
|
||||
linesz = 0;
|
||||
glsz = getline(&line, &linesz, f);
|
||||
fclose(f);
|
||||
|
||||
if (strcasestr(line, "discharging") == line) {
|
||||
on_ac = 0;
|
||||
} else if (strcasestr(line, "charging") == line) {
|
||||
on_ac = 1;
|
||||
charging = 1;
|
||||
}
|
||||
|
||||
free(line);
|
||||
|
||||
itr = 0;
|
||||
while (filepairs[itr].target != NULL) {
|
||||
snprintf(fpath, 128, "%s/%s", bdir, filepairs[itr].filename);
|
||||
|
||||
if ((f = fopen(fpath, "r")) != NULL) {
|
||||
if (fscanf(f, "%lu", filepairs[itr].target) != 1) {
|
||||
*(filepairs[itr].target) = -1L;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
} else {
|
||||
*(filepairs[itr].target) = -1L;
|
||||
}
|
||||
|
||||
itr++;
|
||||
}
|
||||
|
||||
if (charge_now != -1) {
|
||||
remaining_capacity = charge_now / 1000L;
|
||||
} else if (energy_now != -1) {
|
||||
remaining_energy = energy_now / 1000L;
|
||||
}
|
||||
|
||||
if (current_now != -1) {
|
||||
present_rate = current_now / 1000L;
|
||||
} else if (power_now != -1) {
|
||||
present_rate = power_now / 1000L;
|
||||
}
|
||||
|
||||
if (charge_full != -1) {
|
||||
last_capacity = charge_full / 1000L;
|
||||
} else if (energy_full != -1) {
|
||||
last_capacity_unit = energy_full / 1000L;
|
||||
}
|
||||
|
||||
if (voltage_now != -1) {
|
||||
voltage = voltage_now / 1000L;
|
||||
}
|
||||
|
||||
|
||||
if (last_capacity_unit != -1 && last_capacity == -1) {
|
||||
if (voltage == 0) {
|
||||
last_capacity = 0;
|
||||
} else if (voltage != -1) {
|
||||
last_capacity = last_capacity_unit * 1000L / voltage;
|
||||
} else {
|
||||
last_capacity = last_capacity_unit;
|
||||
}
|
||||
}
|
||||
|
||||
if (remaining_energy != -1 && remaining_capacity == -1) {
|
||||
if (voltage == 0) {
|
||||
remaining_capacity = 0;
|
||||
} else if (voltage != -1) {
|
||||
remaining_capacity = remaining_energy * 1000 / voltage;
|
||||
present_rate = present_rate * 1000 / voltage;
|
||||
} else {
|
||||
remaining_capacity = remaining_energy;
|
||||
}
|
||||
}
|
||||
|
||||
if (last_capacity <= 0)
|
||||
percentage = 0;
|
||||
else
|
||||
percentage = remaining_capacity * 100 / last_capacity;
|
||||
|
||||
if (present_rate <= 0)
|
||||
seconds_remaining = 0;
|
||||
else
|
||||
seconds_remaining = 3600 * remaining_capacity / present_rate;
|
||||
|
||||
out->percentage = percentage;
|
||||
out->charging = charging;
|
||||
out->ac = on_ac;
|
||||
out->remaining_sec = seconds_remaining;
|
||||
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Fetch_Battery_Darwin(kis_battery_info *out __attribute__((unused))) {
|
||||
#ifdef SYS_DARWIN
|
||||
// Battery handling code from Kevin Finisterre & Apple specs
|
||||
CFTypeRef blob = IOPSCopyPowerSourcesInfo();
|
||||
CFArrayRef sources = IOPSCopyPowerSourcesList(blob);
|
||||
|
||||
int i, bat_available = 0;
|
||||
CFDictionaryRef pSource = NULL;
|
||||
const void *psValue;
|
||||
|
||||
int acstat = 0, battflag = LCDP_BATT_ABSENT;
|
||||
|
||||
if (CFArrayGetCount(sources) != 0) {
|
||||
for (i = 0; i < CFArrayGetCount(sources); i++) {
|
||||
pSource = IOPSGetPowerSourceDescription(blob,
|
||||
CFArrayGetValueAtIndex(sources, i));
|
||||
if (pSource == NULL)
|
||||
break;
|
||||
|
||||
psValue = (CFStringRef) CFDictionaryGetValue(pSource,
|
||||
CFSTR(kIOPSNameKey));
|
||||
|
||||
if (CFDictionaryGetValueIfPresent(pSource, CFSTR(kIOPSIsPresentKey),
|
||||
&psValue) &&
|
||||
(CFBooleanGetValue((CFBooleanRef) psValue))) {
|
||||
psValue =
|
||||
(CFStringRef) CFDictionaryGetValue(pSource,
|
||||
CFSTR(kIOPSPowerSourceStateKey));
|
||||
|
||||
if (CFStringCompare((CFStringRef) psValue,
|
||||
CFSTR(kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo) {
|
||||
battflag = LCDP_BATT_UNKNOWN;
|
||||
acstat = LCDP_AC_OFF;
|
||||
out->charging = 0;
|
||||
} else if (CFDictionaryGetValueIfPresent(pSource,
|
||||
CFSTR(kIOPSIsChargingKey), &psValue)) {
|
||||
if (CFBooleanGetValue((CFBooleanRef) psValue) > 0) {
|
||||
battflag = LCDP_BATT_CHARGING;
|
||||
out->charging = 1;
|
||||
} else {
|
||||
battflag = LCDP_BATT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
if (battflag != LCDP_BATT_ABSENT) {
|
||||
int curCapacity = 0;
|
||||
int maxCapacity = 0;
|
||||
int remainingTime = 0;
|
||||
int timeToCharge = 0;
|
||||
|
||||
bat_available = 1;
|
||||
|
||||
psValue = CFDictionaryGetValue(pSource,
|
||||
CFSTR(kIOPSCurrentCapacityKey));
|
||||
CFNumberGetValue((CFNumberRef) psValue, kCFNumberSInt32Type,
|
||||
&curCapacity);
|
||||
|
||||
psValue = CFDictionaryGetValue(pSource,
|
||||
CFSTR(kIOPSMaxCapacityKey));
|
||||
CFNumberGetValue((CFNumberRef) psValue, kCFNumberSInt32Type,
|
||||
&maxCapacity);
|
||||
|
||||
out->percentage = (maxCapacity / curCapacity) * 100;
|
||||
|
||||
// If this is 0 we are on AC, if it's a negative we are
|
||||
// "calculating",
|
||||
psValue = CFDictionaryGetValue(pSource,
|
||||
CFSTR(kIOPSTimeToEmptyKey));
|
||||
CFNumberGetValue((CFNumberRef) psValue,
|
||||
kCFNumberSInt32Type, &remainingTime);
|
||||
|
||||
if (remainingTime == 0)
|
||||
out->ac = 1;
|
||||
else
|
||||
out->ac = 0;
|
||||
|
||||
psValue = CFDictionaryGetValue(pSource,
|
||||
CFSTR(kIOPSTimeToFullChargeKey));
|
||||
CFNumberGetValue((CFNumberRef) psValue,
|
||||
kCFNumberSInt32Type, &timeToCharge);
|
||||
|
||||
if (out->charging && timeToCharge > 0) {
|
||||
out->charging = 1;
|
||||
} else if (remainingTime > 0) {
|
||||
out->remaining_sec = remainingTime * 60;
|
||||
out->charging = 0;
|
||||
out->ac = 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Fetch_Battery_OpenBSD(kis_battery_info *out __attribute__((unused))) {
|
||||
#if defined(SYS_OPENBSD) && defined(HAVE_MACHINE_APMVAR_H)
|
||||
struct apm_power_info api;
|
||||
int apmfd;
|
||||
|
||||
if ((apmfd = open("/dev/apm", O_RDONLY)) < 0) {
|
||||
return 1;
|
||||
} else if (ioctl(apmfd, APM_IOC_GETPOWER, &api) < 0) {
|
||||
close(apmfd);
|
||||
return 1;
|
||||
} else {
|
||||
close(apmfd);
|
||||
switch(api.battery_state) {
|
||||
case APM_BATT_UNKNOWN:
|
||||
case APM_BATTERY_ABSENT:
|
||||
return 1;
|
||||
}
|
||||
|
||||
out->percentage = (int) api.battery_life;
|
||||
out->remaining_sec = (int) api.minutes_left * 60;
|
||||
|
||||
if (api.battery_state == APM_BATT_CHARGING) {
|
||||
out->ac = 1;
|
||||
out->charging = 1;
|
||||
} else {
|
||||
switch (api.ac_state) {
|
||||
case APM_AC_ON:
|
||||
out->ac = 1;
|
||||
if (bat_percentage < 100) {
|
||||
out->charging = 1;
|
||||
} else {
|
||||
out->charging = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
out->ac = 0;
|
||||
out->charging = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Fetch_Battery_NetBSD(kis_battery_info *out __attribute__((unused))) {
|
||||
#ifdef SYS_NETBSD
|
||||
static int fd = -1;
|
||||
int i;
|
||||
envsys_basic_info_t info;
|
||||
envsys_tre_data_t data;
|
||||
unsigned int charge = 0;
|
||||
unsigned int maxcharge = 0;
|
||||
unsigned int rate = 0;
|
||||
|
||||
if (fd < 0 && (fd = open(_PATH_SYSMON, O_RDONLY)) < 0)
|
||||
return 1;
|
||||
|
||||
for (i = 0; i >= 0; i++) {
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.sensor = i;
|
||||
|
||||
if (ioctl(fd, ENVSYS_GTREINFO, &info) == -1) {
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(info.validflags & ENVSYS_FVALID))
|
||||
break;
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.sensor = i;
|
||||
|
||||
if(ioctl(fd, ENVSYS_GTREDATA, &data) == -1) {
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(data.validflags & ENVSYS_FVALID))
|
||||
continue;
|
||||
|
||||
if (strcmp("acpiacad0 connected", info.desc) == 0) {
|
||||
out->ac = data.cur.data_us;
|
||||
} else if (strcmp("acpibat0 charge", info.desc) == 0) {
|
||||
out->percentage = (unsigned int) ((data.cur.data_us * 100.0) /
|
||||
data.max.data_us);
|
||||
charge = data.cur.data_us;
|
||||
maxcharge = data.max.data_us;
|
||||
} else if (strcmp("acpibat0 charging", info.desc) == 0) {
|
||||
out->charging = data.cur.data_us > 0 ? 1 : 0;
|
||||
} else if (strcmp("acpibat0 discharge rate", info.desc) == 0) {
|
||||
rate = data.cur.data_us;
|
||||
}
|
||||
}
|
||||
|
||||
if (out->charging != 0)
|
||||
out->remaining_sec = rate ? (unsigned int) ((maxcharge - charge) * 3600.0 /
|
||||
else
|
||||
out->remaining_sec = rate ? (unsigned int) ((charge * 3600.0) / rate) : 0;
|
||||
|
||||
return 1;
|
||||
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Fetch_Battery_Info(kis_battery_info *out) {
|
||||
out->percentage = 0;
|
||||
out->charging = 0;
|
||||
out->remaining_sec = 0;
|
||||
out->ac = 1;
|
||||
|
||||
#ifdef SYS_LINUX
|
||||
if (Fetch_Battery_Linux_ACPI(out))
|
||||
return 1;
|
||||
|
||||
if (Fetch_Battery_Linux_Sys(out))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
|
||||
#elif defined(SYS_DARWIN)
|
||||
return Fetch_Battery_Darwin(out);
|
||||
#elif defined(SYS_OPENBSD) && defined(HAVE_MACHINE_APMVAR_H)
|
||||
return Fetch_Battery_OpenBSD(out);
|
||||
#elif defined(SYS_NETBSD)
|
||||
static int fd = -1;
|
||||
int i;
|
||||
envsys_basic_info_t info;
|
||||
envsys_tre_data_t data;
|
||||
unsigned int charge = 0;
|
||||
unsigned int maxcharge = 0;
|
||||
unsigned int rate = 0;
|
||||
|
||||
if (fd < 0 && (fd = open(_PATH_SYSMON, O_RDONLY)) < 0)
|
||||
return 1;
|
||||
|
||||
for (i = 0; i >= 0; i++) {
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.sensor = i;
|
||||
|
||||
if (ioctl(fd, ENVSYS_GTREINFO, &info) == -1) {
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(info.validflags & ENVSYS_FVALID))
|
||||
break;
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.sensor = i;
|
||||
|
||||
if(ioctl(fd, ENVSYS_GTREDATA, &data) == -1) {
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(data.validflags & ENVSYS_FVALID))
|
||||
continue;
|
||||
|
||||
if (strcmp("acpiacad0 connected", info.desc) == 0) {
|
||||
out->ac = data.cur.data_us;
|
||||
} else if (strcmp("acpibat0 charge", info.desc) == 0) {
|
||||
out->percentage = (unsigned int) ((data.cur.data_us * 100.0) /
|
||||
data.max.data_us);
|
||||
charge = data.cur.data_us;
|
||||
maxcharge = data.max.data_us;
|
||||
} else if (strcmp("acpibat0 charging", info.desc) == 0) {
|
||||
out->charging = data.cur.data_us > 0 ? 1 : 0;
|
||||
} else if (strcmp("acpibat0 discharge rate", info.desc) == 0) {
|
||||
rate = data.cur.data_us;
|
||||
}
|
||||
}
|
||||
|
||||
if (out->charging != 0)
|
||||
out->remaining_sec = rate ? (unsigned int) ((maxcharge - charge) * 3600.0 /
|
||||
rate) : 0;
|
||||
else
|
||||
out->remaining_sec = rate ? (unsigned int) ((charge * 3600.0) / rate) : 0;
|
||||
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __BATTERY_H__
|
||||
#define __BATTERY_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
struct kis_battery_info {
|
||||
int percentage, charging, ac, remaining_sec;
|
||||
};
|
||||
|
||||
int Fetch_Battery_Info(kis_battery_info *out_info);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "bluetooth_parsers/bt_rfinfo.h"
|
||||
|
||||
void bluetooth_radio_info::parse(std::shared_ptr<kaitai::kstream> p_io) {
|
||||
m_rf_channel = p_io->read_u1();
|
||||
m_dbm_signal = p_io->read_u1();
|
||||
m_dbm_noise = p_io->read_u1();
|
||||
m_address_offenses = p_io->read_u1();
|
||||
m_ref_access_address = mac_addr(p_io->read_bytes(4));
|
||||
m_flags = p_io->read_u2le();
|
||||
}
|
||||
|
|
@ -1,112 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __BLUETOOTH_RADIO_INFO_H__
|
||||
#define __BLUETOOTH_RADIO_INFO_H__
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <kaitai/kaitaistream.h>
|
||||
#include "macaddr.h"
|
||||
#include "multi_constexpr.h"
|
||||
|
||||
class bluetooth_radio_info {
|
||||
public:
|
||||
bluetooth_radio_info() { }
|
||||
~bluetooth_radio_info() { }
|
||||
|
||||
void parse(std::shared_ptr<kaitai::kstream> p_io);
|
||||
|
||||
constexpr17 uint8_t rf_channel() const {
|
||||
return m_rf_channel;
|
||||
}
|
||||
|
||||
constexpr17 uint8_t dbm_signal() const {
|
||||
return m_dbm_signal;
|
||||
}
|
||||
|
||||
constexpr17 uint8_t dbm_noise() const {
|
||||
return m_dbm_noise;
|
||||
}
|
||||
|
||||
constexpr17 uint8_t address_offenses() const {
|
||||
return m_address_offenses;
|
||||
}
|
||||
|
||||
mac_addr reference_access_address() const {
|
||||
return m_ref_access_address;
|
||||
}
|
||||
|
||||
constexpr17 uint16_t flags() const {
|
||||
return m_flags;
|
||||
}
|
||||
|
||||
constexpr17 bool flag_whitened() const {
|
||||
return flags() & 0x01;
|
||||
}
|
||||
|
||||
constexpr17 bool flag_signal_valid() const {
|
||||
return flags() & 0x02;
|
||||
}
|
||||
|
||||
constexpr17 bool flag_noise_valid() const {
|
||||
return flags() & 0x04;
|
||||
}
|
||||
|
||||
constexpr17 bool flag_decrypted() const {
|
||||
return flags() & 0x08;
|
||||
}
|
||||
|
||||
constexpr17 bool flag_access_offenses_valid() const {
|
||||
return flags() & 0x10;
|
||||
}
|
||||
|
||||
constexpr17 bool flag_channel_aliased() const {
|
||||
return flags() & 0x20;
|
||||
}
|
||||
|
||||
constexpr17 bool flag_crc_checked() const {
|
||||
return flags() & 0x400;
|
||||
}
|
||||
|
||||
constexpr17 bool flag_crc_valid() const {
|
||||
return flags() & 0x800;
|
||||
}
|
||||
|
||||
constexpr17 bool flag_mic_checked() const {
|
||||
return flags() & 0x1000;
|
||||
}
|
||||
|
||||
constexpr17 bool flag_mic_valid() const {
|
||||
return flags() & 0x2000;
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t m_rf_channel;
|
||||
uint8_t m_dbm_signal;
|
||||
uint8_t m_dbm_noise;
|
||||
uint8_t m_address_offenses;
|
||||
mac_addr m_ref_access_address;
|
||||
uint16_t m_flags;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "boost_like_hash.h"
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#include <kis_endian.h>
|
||||
|
||||
#include "xxhash_cpp.h"
|
||||
|
||||
template<> void boost_like::hash_combine(xxHashCPP& hash, const std::string& val) {
|
||||
hash.update(val.data(), val.length());
|
||||
}
|
||||
|
||||
template<> void boost_like::hash_combine(xxHashCPP& hash, const uint8_t& val) {
|
||||
hash.update(&val, sizeof(uint8_t));
|
||||
}
|
||||
|
||||
template<> void boost_like::hash_combine(xxHashCPP& hash, const int8_t& val) {
|
||||
hash.update(&val, sizeof(int8_t));
|
||||
}
|
||||
|
||||
template<> void boost_like::hash_combine(xxHashCPP& hash, const uint16_t& val) {
|
||||
auto le = htole16(val);
|
||||
hash.update(&le, sizeof(uint16_t));
|
||||
}
|
||||
|
||||
template<> void boost_like::hash_combine(xxHashCPP& hash, const int16_t& val) {
|
||||
auto le = htole16(val);
|
||||
hash.update(&le, sizeof(int16_t));
|
||||
}
|
||||
|
||||
template<> void boost_like::hash_combine(xxHashCPP& hash, const uint32_t& val) {
|
||||
auto le = htole32(val);
|
||||
hash.update(&le, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
template<> void boost_like::hash_combine(xxHashCPP& hash, const int32_t& val) {
|
||||
auto le = htole32(val);
|
||||
hash.update(&le, sizeof(int32_t));
|
||||
}
|
||||
|
||||
template<> void boost_like::hash_combine(xxHashCPP& hash, const uint64_t& val) {
|
||||
auto le = htole64(val);
|
||||
hash.update(&le, sizeof(uint64_t));
|
||||
}
|
||||
|
||||
template<> void boost_like::hash_combine(xxHashCPP& hash, const int64_t& val) {
|
||||
auto le = htole64(val);
|
||||
hash.update(&le, sizeof(int64_t));
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
// Boost-like functionality without bringing in all of boost; we emulate the boost
|
||||
// hash_combine function for instance but plumb it into a consistent xxhash32 engine
|
||||
|
||||
#ifndef __BOOST_LIKE_HASH_H__
|
||||
#define __BOOST_LIKE_HASH_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "xxhash_cpp.h"
|
||||
|
||||
namespace boost_like {
|
||||
|
||||
template<typename T> void hash_combine(xxHashCPP& hash, const T& val);
|
||||
|
||||
template<> void hash_combine(xxHashCPP& hash, const std::string& val);
|
||||
template<> void hash_combine(xxHashCPP& hash, const uint8_t& val);
|
||||
template<> void hash_combine(xxHashCPP& hash, const int8_t& val);
|
||||
template<> void hash_combine(xxHashCPP& hash, const uint16_t& val);
|
||||
template<> void hash_combine(xxHashCPP& hash, const int16_t& val);
|
||||
template<> void hash_combine(xxHashCPP& hash, const uint32_t& val);
|
||||
template<> void hash_combine(xxHashCPP& hash, const int32_t& val);
|
||||
template<> void hash_combine(xxHashCPP& hash, const uint64_t& val);
|
||||
template<> void hash_combine(xxHashCPP& hash, const int64_t& val);
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
void hash_combine(xxHashCPP& hash, const T& arg1, const Ts&... args) {
|
||||
hash_combine(hash, arg1);
|
||||
hash_combine(hash, args...);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,598 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "buffer_handler.h"
|
||||
|
||||
BufferHandlerGeneric::BufferHandlerGeneric() :
|
||||
read_buffer {nullptr},
|
||||
write_buffer {nullptr},
|
||||
wbuf_notify_avail {false},
|
||||
rbuf_notify_avail {false},
|
||||
handler_mutex {std::make_shared<kis_recursive_timed_mutex>()},
|
||||
wbuf_drain_avail {false},
|
||||
rbuf_drain_avail {false},
|
||||
writebuf_drain_cb {nullptr},
|
||||
readbuf_drain_cb {nullptr} { }
|
||||
|
||||
BufferHandlerGeneric::~BufferHandlerGeneric() {
|
||||
if (read_buffer)
|
||||
delete read_buffer;
|
||||
|
||||
if (write_buffer)
|
||||
delete write_buffer;
|
||||
}
|
||||
|
||||
void BufferHandlerGeneric::SetMutex(std::shared_ptr<kis_recursive_timed_mutex> in_parent) {
|
||||
if (in_parent != nullptr && in_parent == handler_mutex)
|
||||
return;
|
||||
|
||||
local_locker l(handler_mutex);
|
||||
|
||||
if (in_parent != nullptr)
|
||||
handler_mutex = in_parent;
|
||||
else
|
||||
handler_mutex = std::make_shared<kis_recursive_timed_mutex>();
|
||||
}
|
||||
|
||||
ssize_t BufferHandlerGeneric::GetReadBufferSize() {
|
||||
if (read_buffer)
|
||||
return read_buffer->size();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t BufferHandlerGeneric::GetWriteBufferSize() {
|
||||
if (write_buffer)
|
||||
return write_buffer->size();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t BufferHandlerGeneric::GetReadBufferUsed() {
|
||||
if (read_buffer)
|
||||
return read_buffer->used();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t BufferHandlerGeneric::GetWriteBufferUsed() {
|
||||
if (write_buffer)
|
||||
return write_buffer->used();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t BufferHandlerGeneric::GetReadBufferAvailable() {
|
||||
if (read_buffer)
|
||||
return read_buffer->available();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t BufferHandlerGeneric::GetWriteBufferAvailable() {
|
||||
if (write_buffer)
|
||||
return write_buffer->available();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t BufferHandlerGeneric::PeekReadBufferData(void **in_ptr, size_t in_sz) {
|
||||
if (in_ptr == NULL)
|
||||
return 0;
|
||||
|
||||
if (read_buffer)
|
||||
return read_buffer->peek((unsigned char **) in_ptr, in_sz);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t BufferHandlerGeneric::PeekWriteBufferData(void **in_ptr, size_t in_sz) {
|
||||
if (write_buffer)
|
||||
return write_buffer->peek((unsigned char **) in_ptr, in_sz);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t BufferHandlerGeneric::ZeroCopyPeekReadBufferData(void **in_ptr, size_t in_sz) {
|
||||
if (in_ptr == NULL)
|
||||
return 0;
|
||||
|
||||
if (read_buffer)
|
||||
return read_buffer->zero_copy_peek((unsigned char **) in_ptr, in_sz);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t BufferHandlerGeneric::ZeroCopyPeekWriteBufferData(void **in_ptr, size_t in_sz) {
|
||||
if (write_buffer)
|
||||
return write_buffer->zero_copy_peek((unsigned char **) in_ptr, in_sz);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BufferHandlerGeneric::PeekFreeReadBufferData(void *in_ptr) {
|
||||
if (read_buffer)
|
||||
return read_buffer->peek_free((unsigned char *) in_ptr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void BufferHandlerGeneric::PeekFreeWriteBufferData(void *in_ptr) {
|
||||
if (write_buffer)
|
||||
return write_buffer->peek_free((unsigned char *) in_ptr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
size_t BufferHandlerGeneric::ConsumeReadBufferData(size_t in_sz) {
|
||||
size_t sz;
|
||||
|
||||
if (read_buffer) {
|
||||
sz = read_buffer->consume(in_sz);
|
||||
|
||||
if (rbuf_drain_avail && readbuf_drain_cb) {
|
||||
readbuf_drain_cb(sz);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t BufferHandlerGeneric::ConsumeWriteBufferData(size_t in_sz) {
|
||||
size_t sz;
|
||||
|
||||
if (write_buffer) {
|
||||
sz = write_buffer->consume(in_sz);
|
||||
|
||||
if (wbuf_drain_avail && writebuf_drain_cb) {
|
||||
writebuf_drain_cb(sz);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
size_t BufferHandlerGeneric::PutReadBufferData(void *in_ptr, size_t in_sz,
|
||||
bool in_atomic) {
|
||||
size_t ret;
|
||||
|
||||
{
|
||||
local_locker hlock(handler_mutex);
|
||||
|
||||
if (!read_buffer)
|
||||
return 0;
|
||||
|
||||
// Don't write any if we're an atomic complete write; buffers which report
|
||||
// -1 for available size are infinite
|
||||
if (in_atomic && read_buffer->available() >= 0 &&
|
||||
(size_t) read_buffer->available() < in_sz)
|
||||
return 0;
|
||||
|
||||
ret = read_buffer->write((unsigned char *) in_ptr, in_sz);
|
||||
|
||||
}
|
||||
|
||||
if (rbuf_notify_avail && rbuf_notify) {
|
||||
if (ret != in_sz)
|
||||
rbuf_notify->BufferError("insufficient space in buffer");
|
||||
rbuf_notify->BufferAvailable(ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool BufferHandlerGeneric::PutReadBufferData(std::string in_data) {
|
||||
size_t r =
|
||||
PutReadBufferData((void *) in_data.data(), in_data.length(), true);
|
||||
return (r == in_data.length());
|
||||
}
|
||||
|
||||
bool BufferHandlerGeneric::PutWriteBufferData(std::string in_data) {
|
||||
size_t r =
|
||||
PutWriteBufferData((void *) in_data.data(), in_data.length(), true);
|
||||
return (r == in_data.length());
|
||||
}
|
||||
|
||||
|
||||
size_t BufferHandlerGeneric::PutWriteBufferData(void *in_ptr, size_t in_sz, bool in_atomic) {
|
||||
size_t ret;
|
||||
|
||||
{
|
||||
local_locker hlock(handler_mutex);
|
||||
|
||||
if (!write_buffer) {
|
||||
if (wbuf_notify)
|
||||
wbuf_notify->BufferError("No write buffer connected");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Don't write any if we're an atomic complete write; buffers which report
|
||||
// -1 for available size are infinite
|
||||
if (in_atomic && write_buffer->available() >= 0 &&
|
||||
(size_t) write_buffer->available() < in_sz)
|
||||
return 0;
|
||||
|
||||
ret = write_buffer->write((unsigned char *) in_ptr, in_sz);
|
||||
}
|
||||
|
||||
if (wbuf_notify_avail && wbuf_notify) {
|
||||
if (ret != in_sz)
|
||||
wbuf_notify->BufferError("insufficient space in buffer");
|
||||
|
||||
wbuf_notify->BufferAvailable(ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t BufferHandlerGeneric::ReserveReadBufferData(void **in_ptr, size_t in_sz) {
|
||||
local_locker hlock(handler_mutex);
|
||||
|
||||
if (read_buffer != NULL) {
|
||||
return read_buffer->reserve((unsigned char **) in_ptr, in_sz);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t BufferHandlerGeneric::ReserveWriteBufferData(void **in_ptr, size_t in_sz) {
|
||||
local_locker hlock(handler_mutex);
|
||||
|
||||
if (write_buffer != NULL) {
|
||||
return write_buffer->reserve((unsigned char **) in_ptr, in_sz);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t BufferHandlerGeneric::ZeroCopyReserveReadBufferData(void **in_ptr, size_t in_sz) {
|
||||
local_locker hlock(handler_mutex);
|
||||
|
||||
if (read_buffer != NULL) {
|
||||
return read_buffer->zero_copy_reserve((unsigned char **) in_ptr, in_sz);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t BufferHandlerGeneric::ZeroCopyReserveWriteBufferData(void **in_ptr, size_t in_sz) {
|
||||
local_locker hlock(handler_mutex);
|
||||
|
||||
if (write_buffer != NULL) {
|
||||
return write_buffer->zero_copy_reserve((unsigned char **) in_ptr, in_sz);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void BufferHandlerGeneric::TriggerWriteCallback(size_t in_sz) {
|
||||
if (wbuf_notify_avail && wbuf_notify) {
|
||||
wbuf_notify->BufferAvailable(in_sz);
|
||||
}
|
||||
}
|
||||
|
||||
void BufferHandlerGeneric::TriggerReadCallback(size_t in_sz) {
|
||||
if (rbuf_notify_avail && rbuf_notify) {
|
||||
rbuf_notify->BufferAvailable(in_sz);
|
||||
}
|
||||
}
|
||||
|
||||
bool BufferHandlerGeneric::CommitReadBufferData(void *in_ptr, size_t in_sz) {
|
||||
bool s = false;
|
||||
|
||||
{
|
||||
local_locker hlock(handler_mutex);
|
||||
|
||||
if (read_buffer != NULL) {
|
||||
s = read_buffer->commit((unsigned char *) in_ptr, in_sz);
|
||||
}
|
||||
}
|
||||
|
||||
if (rbuf_notify_avail && rbuf_notify) {
|
||||
if (!s)
|
||||
rbuf_notify->BufferError("error committing to read buffer");
|
||||
else
|
||||
rbuf_notify->BufferAvailable(in_sz);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
bool BufferHandlerGeneric::CommitWriteBufferData(void *in_ptr, size_t in_sz) {
|
||||
bool s = false;
|
||||
|
||||
{
|
||||
local_locker hlock(handler_mutex);
|
||||
if (write_buffer != NULL) {
|
||||
s = write_buffer->commit((unsigned char *) in_ptr, in_sz);
|
||||
}
|
||||
}
|
||||
|
||||
if (wbuf_notify_avail && wbuf_notify) {
|
||||
if (!s)
|
||||
wbuf_notify->BufferError("error committing to write buffer");
|
||||
else
|
||||
wbuf_notify->BufferAvailable(in_sz);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void BufferHandlerGeneric::ClearReadBuffer() {
|
||||
if (read_buffer)
|
||||
read_buffer->clear();
|
||||
}
|
||||
|
||||
void BufferHandlerGeneric::ClearWriteBuffer() {
|
||||
if (write_buffer)
|
||||
write_buffer->clear();
|
||||
}
|
||||
|
||||
void BufferHandlerGeneric::SetReadBufferInterface(BufferInterface *in_interface) {
|
||||
rbuf_notify_avail = false;
|
||||
rbuf_notify = in_interface;
|
||||
rbuf_notify_avail = true;
|
||||
|
||||
size_t pending = GetReadBufferUsed();
|
||||
if (pending)
|
||||
rbuf_notify->BufferAvailable(pending);
|
||||
}
|
||||
|
||||
void BufferHandlerGeneric::SetWriteBufferInterface(BufferInterface *in_interface) {
|
||||
wbuf_notify_avail = false;
|
||||
wbuf_notify = in_interface;
|
||||
wbuf_notify_avail = true;
|
||||
|
||||
size_t pending = GetWriteBufferUsed();
|
||||
|
||||
if (pending)
|
||||
wbuf_notify->BufferAvailable(pending);
|
||||
}
|
||||
|
||||
void BufferHandlerGeneric::RemoveReadBufferInterface() {
|
||||
rbuf_notify_avail = false;
|
||||
rbuf_notify = nullptr;
|
||||
}
|
||||
|
||||
void BufferHandlerGeneric::RemoveWriteBufferInterface() {
|
||||
wbuf_notify_avail = false;
|
||||
wbuf_notify = nullptr;
|
||||
}
|
||||
|
||||
void BufferHandlerGeneric::SetReadBufferDrainCb(std::function<void (size_t)> in_cb) {
|
||||
rbuf_drain_avail = false;
|
||||
readbuf_drain_cb = in_cb;
|
||||
rbuf_drain_avail = true;
|
||||
}
|
||||
|
||||
void BufferHandlerGeneric::SetWriteBufferDrainCb(std::function<void (size_t)> in_cb) {
|
||||
wbuf_drain_avail = false;
|
||||
writebuf_drain_cb = in_cb;
|
||||
wbuf_drain_avail = true;
|
||||
}
|
||||
|
||||
void BufferHandlerGeneric::RemoveReadBufferDrainCb() {
|
||||
rbuf_drain_avail = false;
|
||||
readbuf_drain_cb = nullptr;
|
||||
}
|
||||
|
||||
void BufferHandlerGeneric::RemoveWriteBufferDrainCb() {
|
||||
wbuf_drain_avail = false;
|
||||
writebuf_drain_cb = nullptr;
|
||||
}
|
||||
|
||||
void BufferHandlerGeneric::BufferError(std::string in_error) {
|
||||
ReadBufferError(in_error);
|
||||
WriteBufferError(in_error);
|
||||
}
|
||||
|
||||
void BufferHandlerGeneric::ReadBufferError(std::string in_error) {
|
||||
if (rbuf_notify_avail && rbuf_notify)
|
||||
rbuf_notify->BufferError(in_error);
|
||||
}
|
||||
|
||||
void BufferHandlerGeneric::WriteBufferError(std::string in_error) {
|
||||
if (wbuf_notify_avail && wbuf_notify)
|
||||
wbuf_notify->BufferError(in_error);
|
||||
}
|
||||
|
||||
void BufferHandlerGeneric::SetProtocolErrorCb(std::function<void (void)> in_cb) {
|
||||
local_locker lock(handler_mutex);
|
||||
|
||||
protoerror_cb = in_cb;
|
||||
}
|
||||
|
||||
void BufferHandlerGeneric::ProtocolError() {
|
||||
// Use a write locker because future things may need RW access, too
|
||||
local_locker lock(handler_mutex);
|
||||
|
||||
if (protoerror_cb != NULL)
|
||||
protoerror_cb();
|
||||
|
||||
}
|
||||
|
||||
BufferInterface::BufferInterface() {
|
||||
buffer_handler = NULL;
|
||||
read_handler = false;
|
||||
write_handler = false;
|
||||
}
|
||||
|
||||
BufferInterface::~BufferInterface() {
|
||||
if (buffer_handler != NULL) {
|
||||
if (read_handler)
|
||||
buffer_handler->RemoveReadBufferInterface();
|
||||
if (write_handler)
|
||||
buffer_handler->RemoveWriteBufferInterface();
|
||||
}
|
||||
}
|
||||
|
||||
BufferHandlerOStreambuf::~BufferHandlerOStreambuf() {
|
||||
if (rb_handler != NULL) {
|
||||
rb_handler->RemoveWriteBufferDrainCb();
|
||||
rb_handler = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
std::streamsize BufferHandlerOStreambuf::xsputn(const char_type *s, std::streamsize n) {
|
||||
if (rb_handler == NULL) {
|
||||
// fprintf(stderr, "debug - no rb handler\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// fprintf(stderr, "debug - ostreambuf putting %lu\n", n);
|
||||
ssize_t written = rb_handler->PutWriteBufferData((void *) s, (size_t) n, true);
|
||||
|
||||
if (written == n)
|
||||
return n;
|
||||
|
||||
// fprintf(stderr, "debug - ostreambuf couldn't put all, blocking?\n");
|
||||
|
||||
// If we couldn't write it all into the buffer, flag a full error
|
||||
if (written != n && !blocking) {
|
||||
rb_handler->BufferError("write buffer full, streambuf unable to write data");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Otherwise go into a loop, blocking, until we've written the entire buffer...
|
||||
|
||||
// Initialize the locking variable
|
||||
blocking_cl.reset(new conditional_locker<size_t>());
|
||||
|
||||
// Set a write completion callback
|
||||
rb_handler->SetWriteBufferDrainCb([this](size_t amt __attribute__((unused))) {
|
||||
blocking_cl->unlock(amt);
|
||||
});
|
||||
|
||||
// Jump as far as we managed to write
|
||||
ssize_t wpos = written;
|
||||
while (1) {
|
||||
written = rb_handler->PutWriteBufferData((void *) (s + wpos), n - wpos, true);
|
||||
|
||||
if (wpos + written == n) {
|
||||
rb_handler->RemoveWriteBufferDrainCb();
|
||||
return n;
|
||||
}
|
||||
|
||||
// Keep track of where we are
|
||||
wpos += written;
|
||||
|
||||
// Block until the buffer flushes
|
||||
blocking_cl->block_until();
|
||||
}
|
||||
|
||||
rb_handler->RemoveWriteBufferDrainCb();
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
BufferHandlerOStreambuf::int_type BufferHandlerOStreambuf::overflow(int_type ch) {
|
||||
if (rb_handler == NULL)
|
||||
return -1;
|
||||
|
||||
if (rb_handler->PutWriteBufferData((void *) &ch, 1, true) == 1)
|
||||
return 1;
|
||||
|
||||
// Not blocking, nothing we can do
|
||||
if (!blocking) {
|
||||
rb_handler->BufferError("write buffer full, streambuf unable to write data");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Initialize the locking variable
|
||||
blocking_cl.reset(new conditional_locker<size_t>());
|
||||
|
||||
// Set a write completion callback
|
||||
rb_handler->SetWriteBufferDrainCb([this](size_t amt __attribute__((unused))) {
|
||||
blocking_cl->unlock(amt);
|
||||
});
|
||||
|
||||
while (1) {
|
||||
if (rb_handler->PutWriteBufferData((void *) &ch, 1, true) == 1) {
|
||||
rb_handler->RemoveWriteBufferDrainCb();
|
||||
return 1;
|
||||
}
|
||||
|
||||
blocking_cl->block_until();
|
||||
}
|
||||
|
||||
rb_handler->RemoveWriteBufferDrainCb();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
BufferHandlerOStringStreambuf::~BufferHandlerOStringStreambuf() {
|
||||
rb_handler = NULL;
|
||||
}
|
||||
|
||||
std::streamsize BufferHandlerOStringStreambuf::xsputn(const char_type *s, std::streamsize n) {
|
||||
local_locker l(&mutex);
|
||||
|
||||
std::streamsize sz = std::stringbuf::xsputn(s, n);
|
||||
|
||||
// fmt::print(stderr, "DEBUG - ostringstreambuf put {}\n", n);
|
||||
|
||||
if (str().length() >= 1024) {
|
||||
sync();
|
||||
}
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
BufferHandlerOStringStreambuf::int_type BufferHandlerOStringStreambuf::overflow(int_type ch) {
|
||||
local_locker l(&mutex);
|
||||
|
||||
BufferHandlerOStringStreambuf::int_type it = std::stringbuf::overflow(ch);
|
||||
|
||||
if (str().length() >= 1024) {
|
||||
sync();
|
||||
}
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
int BufferHandlerOStringStreambuf::sync() {
|
||||
if (rb_handler == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
local_locker l(&mutex);
|
||||
|
||||
size_t sz = str().length();
|
||||
|
||||
// fmt::print(stderr, "debug - ostringstreambuf sync {}\n", sz);
|
||||
|
||||
ssize_t written =
|
||||
rb_handler->PutWriteBufferData((void *) str().data(), sz, true);
|
||||
|
||||
if (written != (ssize_t) sz) {
|
||||
// fprintf(stderr, "debug - ostringstreambuf couldn't write temp string, wrote %lu of %lu\n", written, sz);
|
||||
return -1;
|
||||
}
|
||||
|
||||
str("");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,443 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __RINGBUFFER_HANDLER__
|
||||
#define __RINGBUFFER_HANDLER__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <streambuf>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include "util.h"
|
||||
#include "kis_mutex.h"
|
||||
|
||||
class BufferInterface;
|
||||
|
||||
// Common minimal API for a buffer
|
||||
class CommonBuffer {
|
||||
public:
|
||||
CommonBuffer() :
|
||||
write_reserved {false},
|
||||
peek_reserved {false} { }
|
||||
|
||||
virtual ~CommonBuffer() { };
|
||||
|
||||
// Clear all data (and free memory used, for dynamic buffers)
|
||||
virtual void clear() = 0;
|
||||
|
||||
// Fetch total size of buffer; -1 indicates unbounded dynamic buffer
|
||||
virtual ssize_t size() = 0;
|
||||
|
||||
// Fetch available space in buffer, -1 indicates unbounded dynamic buffer
|
||||
virtual ssize_t available() = 0;
|
||||
|
||||
// Fetch amount used in current buffer
|
||||
virtual size_t used() = 0;
|
||||
|
||||
// Reserve space in the write buffer; for fixed-size buffers such as a ringbuf this
|
||||
// will reserve the space and provide a direct pointer to the space. For continual
|
||||
// dynamic buffers (like chainbuf) this may induce copy or may provide direct access.
|
||||
// Callers should not make any assumptions about the underlying nature of the buffer.
|
||||
//
|
||||
// The reserved space is provided in a data pointer; this object must be
|
||||
// returned to the buffer via commit()
|
||||
//
|
||||
// This data pointer may be a direct link (zero-copy) to the buffer, or may
|
||||
// require an additional memory copy.
|
||||
//
|
||||
// Only one reservation may be made at a time. Additional reservations without a
|
||||
// commit should fail.
|
||||
//
|
||||
// Implementations must track internally if the reserved data must be free'd upon commit
|
||||
//
|
||||
// Implementations should protect cross-thread reservations via write_mutex
|
||||
virtual ssize_t reserve(unsigned char **data, size_t in_sz) = 0;
|
||||
|
||||
// Reserve as much space as possible, up to in_sz, and do as much as possible to
|
||||
// ensure it is a zero-copy buffer.
|
||||
//
|
||||
// A zero-copy reservation may be smaller than the requested reservation size.
|
||||
//
|
||||
// Only one reservation may be made at a time.
|
||||
//
|
||||
// The caller must commit the reserved data.
|
||||
//
|
||||
// Implementations should protect cross-thread reservations via write_mutex
|
||||
virtual ssize_t zero_copy_reserve(unsigned char **data, size_t in_sz) = 0;
|
||||
|
||||
// Commit changes to the reserved block
|
||||
//
|
||||
// Implementations should release the write_mutex lock
|
||||
virtual bool commit(unsigned char *data, size_t in_sz) = 0;
|
||||
|
||||
// Write an existing block of data to the buffer; this always performs a memcpy to copy
|
||||
// the data into the buffer. When possible, it is more efficient to use the
|
||||
// reservation system.
|
||||
//
|
||||
// Implementations should protect cross-thread reservations via write_mutex
|
||||
virtual ssize_t write(unsigned char *data, size_t in_sz) = 0;
|
||||
|
||||
// Peek data. If possible, this will be a zero-copy operation, if not, it will
|
||||
// allocate a buffer. Content is returned in the **data pointer, which will be
|
||||
// a buffer of at least the returned size; Peeking may return less data
|
||||
// than requested.
|
||||
//
|
||||
// Callers MUST free the data with 'peek_free(...)'. Buffer implementations MUST
|
||||
// track if the peeked data must be deleted or if it is a zero-copy reference.
|
||||
//
|
||||
// Only one piece of data should be peek'd at a time, additional attempts prior
|
||||
// to a peek_free may fail. This includes peek() and zero_copy_peek()
|
||||
//
|
||||
// peek will perform a copy to fulfill the total data size if the underlying
|
||||
// buffer implementation cannot return a zero-copy reference; as such it is most
|
||||
// appropriate for performing read operations of structured data where the entire
|
||||
// object must be available.
|
||||
//
|
||||
// implementations should protect peek data cross-thread using the peek_mutex
|
||||
virtual ssize_t peek(unsigned char **data, size_t in_sz) = 0;
|
||||
|
||||
// Attempt a zero-copy peek; if the underlying buffer supports zero-copy references
|
||||
// this will return a direct pointer to the buffer contents; if the underlying buffer
|
||||
// does not, it may allocate memory and perform a copy.
|
||||
//
|
||||
// Callers MUST free the data with 'peek_free(...)'. Buffer implementations MUST
|
||||
// track if the peeked data must be deleted or if it is a zero-copy reference.
|
||||
//
|
||||
// zero_copy_peek will NEVER allocate and copy a buffer when a no-copy shorter
|
||||
// buffer is available; This is most suited for draining buffers to an IO system
|
||||
// where the exact record length is not relevant; in general it is not as useful
|
||||
// when a fixed record size must be available.
|
||||
//
|
||||
// Only one piece of data should be peek'd at a time, additional attempts prior
|
||||
// to a peek_free may fail; this includes peek() and zero_copy_peek()
|
||||
//
|
||||
// implementations should protect peek data cross-thread using the peek_mutex
|
||||
virtual ssize_t zero_copy_peek(unsigned char **data, size_t in_sz) = 0;
|
||||
|
||||
// Deallocate peeked data; implementations should also use this time to release
|
||||
// the peek_mutex lock on peek data
|
||||
virtual void peek_free(unsigned char *data) = 0;
|
||||
|
||||
// Remove data from a buffer
|
||||
virtual size_t consume(size_t in_sz) = 0;
|
||||
|
||||
protected:
|
||||
std::atomic<bool> write_reserved;
|
||||
std::atomic<bool> peek_reserved;
|
||||
|
||||
// Additional mutex for protecting peek and write reservations across threads
|
||||
kis_recursive_timed_mutex peek_mutex, write_mutex;
|
||||
};
|
||||
|
||||
// Common handler for a buffer, which allows a simple standardized interface
|
||||
// to the buffer when data is added. Typically used with a Ringbuffer or a
|
||||
// Chainbuffer (When using a chainbuffer, be aware of the chainbuf limitations)
|
||||
//
|
||||
// Anything that handles async / nonblocking data can use this interface.
|
||||
//
|
||||
// Network servers and consumers should communicate by defining buffer
|
||||
// interfaces
|
||||
//
|
||||
// Typically a buffer handler is created for each async communication task
|
||||
// (ie client connection, server socket, serial port, etc) and connected to
|
||||
// the low-level IO driver (often a Pollable) which reads and writes directly
|
||||
// to the ring buffers. The buffer handler then automatically calls bound
|
||||
// handlers for read/write events.
|
||||
//
|
||||
class BufferHandlerGenericLocker;
|
||||
|
||||
class BufferHandlerGeneric {
|
||||
public:
|
||||
BufferHandlerGeneric();
|
||||
virtual ~BufferHandlerGeneric();
|
||||
|
||||
virtual void SetMutex(std::shared_ptr<kis_recursive_timed_mutex> in_parent);
|
||||
|
||||
// Basic size ops
|
||||
virtual ssize_t GetReadBufferSize();
|
||||
virtual ssize_t GetWriteBufferSize();
|
||||
|
||||
virtual size_t GetReadBufferUsed();
|
||||
virtual size_t GetWriteBufferUsed();
|
||||
|
||||
virtual ssize_t GetReadBufferAvailable();
|
||||
virtual ssize_t GetWriteBufferAvailable();
|
||||
|
||||
// Fetch read and write buffer data, up to in_amt. Does not consume data.
|
||||
// When possible, minimizes copies; actual copy and memory use depends on the
|
||||
// lower-level buffer, and consumers should not rely on specific behaviors.
|
||||
//
|
||||
// Consumers MUST conclude a peek operation with PeekFreeReadBufferData(...) or
|
||||
// PeekFreeWriteBufferData(...), and may not perform multiple peeks simultaneously;
|
||||
// refer to the comments for CommonBuffer
|
||||
//
|
||||
// Returns amount peeked
|
||||
virtual ssize_t PeekReadBufferData(void **in_ptr, size_t in_sz);
|
||||
virtual ssize_t PeekWriteBufferData(void **in_ptr, size_t in_sz);
|
||||
|
||||
// Perform a zero-copy (when possible) peek of the buffer. Does not consume
|
||||
// data. When possible, minimizes copying of data (or performs no copy of data),
|
||||
// and is suitable for draining a buffer to the IO system.
|
||||
virtual ssize_t ZeroCopyPeekReadBufferData(void **in_ptr, size_t in_sz);
|
||||
virtual ssize_t ZeroCopyPeekWriteBufferData(void **in_ptr, size_t in_sz);
|
||||
|
||||
virtual void PeekFreeReadBufferData(void *in_ptr);
|
||||
virtual void PeekFreeWriteBufferData(void *in_ptr);
|
||||
|
||||
// Consume data from the buffer. Must not be called while there is pending 'peek'd
|
||||
// data.
|
||||
//
|
||||
// Automatically triggers buffer drain callbacks
|
||||
virtual size_t ConsumeReadBufferData(size_t in_sz);
|
||||
virtual size_t ConsumeWriteBufferData(size_t in_sz);
|
||||
|
||||
// Place data in read or write buffer. Performs a copy of the existing data and
|
||||
// writes it into the buffer.
|
||||
//
|
||||
// Automatically triggers callbacks
|
||||
//
|
||||
// Returns amount of data actually written
|
||||
virtual size_t PutReadBufferData(void *in_ptr, size_t in_sz, bool in_atomic);
|
||||
virtual size_t PutWriteBufferData(void *in_ptr, size_t in_sz, bool in_atomic);
|
||||
|
||||
// Place data, as a string, into the buffer as an atomic op; returns success
|
||||
// or failure on placing the entire record.
|
||||
virtual bool PutReadBufferData(std::string in_data);
|
||||
virtual bool PutWriteBufferData(std::string in_data);
|
||||
|
||||
// Reserve space in the buffers; the returned pointer is suitable for direct
|
||||
// writing. Whenever possible, this will be a zero-copy operation, however on
|
||||
// some buffer structures this may require copying of the data content to the
|
||||
// buffer.
|
||||
//
|
||||
// Callers must not make assumptions about the underlying structure of the buffer
|
||||
// or of the pointer they are given.
|
||||
//
|
||||
// Callers must conclude the write operation with CommitReadBufferData(..) or
|
||||
// CommitWriteBufferData(..).
|
||||
//
|
||||
// Only one block of data may be reserved at a time.
|
||||
//
|
||||
// Returns the amount of data allocated in the reserved block
|
||||
virtual ssize_t ReserveReadBufferData(void **in_ptr, size_t len);
|
||||
virtual ssize_t ReserveWriteBufferData(void **in_ptr, size_t len);
|
||||
|
||||
// Reserve space in one of the buffers; Take excessive measures to make this a
|
||||
// zero-copy buffer, including reserving less size than requested. This is most
|
||||
// appropriate for incoming data streams being written to a buffer.
|
||||
//
|
||||
// Callers must conclude the write operation with CommitReadBufferData(..) or
|
||||
// CommitWriteBufferData(..)
|
||||
//
|
||||
// Only one block of data may be reserved at a time.
|
||||
//
|
||||
// Returns the amount of data available in the reserved block
|
||||
virtual ssize_t ZeroCopyReserveReadBufferData(void **in_ptr, size_t len);
|
||||
virtual ssize_t ZeroCopyReserveWriteBufferData(void **in_ptr, size_t len);
|
||||
|
||||
|
||||
// Commit a pending reserved data block to the buffer
|
||||
//
|
||||
// Automatically triggers callbacks.
|
||||
virtual bool CommitReadBufferData(void *in_ptr, size_t in_sz);
|
||||
virtual bool CommitWriteBufferData(void *in_ptr, size_t in_sz);
|
||||
|
||||
|
||||
// Clear a buffer
|
||||
//
|
||||
// Completely empties a buffer, possibly freeing any memory associated with it
|
||||
// if it's a dynamic buffer
|
||||
virtual void ClearReadBuffer();
|
||||
virtual void ClearWriteBuffer();
|
||||
|
||||
// Trigger callbacks directly
|
||||
virtual void TriggerWriteCallback(size_t in_sz);
|
||||
virtual void TriggerReadCallback(size_t in_sz);
|
||||
|
||||
// Set interface callbacks to be called when we have data in the buffers
|
||||
virtual void SetReadBufferInterface(BufferInterface *in_interface);
|
||||
virtual void SetWriteBufferInterface(BufferInterface *in_interface);
|
||||
|
||||
virtual void RemoveReadBufferInterface();
|
||||
virtual void RemoveWriteBufferInterface();
|
||||
|
||||
// Set simple functional callbacks to be called when we drain an interface; used to
|
||||
// allow quick unlocking of blocked writers
|
||||
virtual void SetReadBufferDrainCb(std::function<void (size_t)> in_cb);
|
||||
virtual void SetWriteBufferDrainCb(std::function<void (size_t)> in_cb);
|
||||
|
||||
virtual void RemoveReadBufferDrainCb();
|
||||
virtual void RemoveWriteBufferDrainCb();
|
||||
|
||||
// Propagate a line-layer buffer error to any listeners (line IO system to interfaces)
|
||||
virtual void BufferError(std::string in_error);
|
||||
// Propagate an error to a specific listener
|
||||
virtual void ReadBufferError(std::string in_error);
|
||||
virtual void WriteBufferError(std::string in_error);
|
||||
|
||||
// Propagate a protocol-layer error to any line-drivers (protocol parser
|
||||
// to line drivers). We don't pass a string to the line drivers because
|
||||
// the protocol driver should present the error usefully
|
||||
virtual void ProtocolError();
|
||||
// Set a protocol error callback; line level drivers should set this and initiate
|
||||
// a shutdown of the line connections
|
||||
virtual void SetProtocolErrorCb(std::function<void (void)> in_cb);
|
||||
|
||||
friend class BufferHandlerGenericLocker;
|
||||
|
||||
protected:
|
||||
// Generic buffers
|
||||
CommonBuffer *read_buffer;
|
||||
CommonBuffer *write_buffer;
|
||||
|
||||
// Interfaces we notify when there has been activity on a buffer; use atomic booleans
|
||||
// to indicate if the function is available
|
||||
std::atomic<bool> wbuf_notify_avail, rbuf_notify_avail;
|
||||
BufferInterface *wbuf_notify;
|
||||
BufferInterface *rbuf_notify;
|
||||
|
||||
std::shared_ptr<kis_recursive_timed_mutex> handler_mutex;
|
||||
|
||||
std::function<void (void)> protoerror_cb;
|
||||
|
||||
std::atomic<bool> wbuf_drain_avail, rbuf_drain_avail;
|
||||
std::function<void (size_t)> writebuf_drain_cb;
|
||||
std::function<void (size_t)> readbuf_drain_cb;
|
||||
};
|
||||
|
||||
template<class B>
|
||||
class BufferHandler : public BufferHandlerGeneric {
|
||||
public:
|
||||
// For one-way buffers, define a buffer as having a size of zero
|
||||
BufferHandler(size_t r_buffer_sz, size_t w_buffer_sz) {
|
||||
if (r_buffer_sz != 0)
|
||||
read_buffer = new B(r_buffer_sz);
|
||||
else
|
||||
read_buffer = NULL;
|
||||
|
||||
if (w_buffer_sz != 0)
|
||||
write_buffer = new B(w_buffer_sz);
|
||||
else
|
||||
write_buffer = NULL;
|
||||
}
|
||||
|
||||
BufferHandler(B *r_buf, B *w_buf) {
|
||||
read_buffer = r_buf;
|
||||
write_buffer = w_buf;
|
||||
}
|
||||
};
|
||||
|
||||
// A C++ streambuf-compatible wrapper around a buf handler
|
||||
struct BufferHandlerOStreambuf : public std::streambuf {
|
||||
BufferHandlerOStreambuf(std::shared_ptr<BufferHandlerGeneric > in_rbhandler) :
|
||||
rb_handler(in_rbhandler), blocking(false) { }
|
||||
BufferHandlerOStreambuf(std::shared_ptr<BufferHandlerGeneric > in_rbhandler, bool in_blocking) :
|
||||
rb_handler(in_rbhandler), blocking(in_blocking) { }
|
||||
|
||||
virtual ~BufferHandlerOStreambuf();
|
||||
|
||||
protected:
|
||||
std::streamsize xsputn(const char_type *s, std::streamsize n) override;
|
||||
int_type overflow(int_type ch) override;
|
||||
|
||||
private:
|
||||
// buf handler we bind to
|
||||
std::shared_ptr<BufferHandlerGeneric > rb_handler;
|
||||
|
||||
// Do we block when buffer is full?
|
||||
bool blocking;
|
||||
|
||||
// Locker variable if we block
|
||||
std::shared_ptr<conditional_locker<size_t> > blocking_cl;
|
||||
};
|
||||
|
||||
// A C++ streambuf-compatible wrapper around a buf handler with an interstitial string
|
||||
// cache
|
||||
struct BufferHandlerOStringStreambuf : public std::stringbuf {
|
||||
BufferHandlerOStringStreambuf(std::shared_ptr<BufferHandlerGeneric > in_rbhandler) :
|
||||
rb_handler(in_rbhandler) { }
|
||||
|
||||
virtual ~BufferHandlerOStringStreambuf();
|
||||
|
||||
protected:
|
||||
// Wrap the stringbuf functions
|
||||
std::streamsize xsputn(const char_type *s, std::streamsize n) override;
|
||||
int_type overflow(int_type ch) override;
|
||||
|
||||
int sync() override;
|
||||
|
||||
private:
|
||||
kis_recursive_timed_mutex mutex;
|
||||
|
||||
// buf handler we bind to
|
||||
std::shared_ptr<BufferHandlerGeneric > rb_handler;
|
||||
|
||||
};
|
||||
|
||||
|
||||
// buffer interface, interacts with a buffer handler
|
||||
class BufferInterface {
|
||||
public:
|
||||
BufferInterface();
|
||||
virtual ~BufferInterface();
|
||||
|
||||
// Called when the linked buffer has new data available
|
||||
virtual void BufferAvailable(size_t in_amt) = 0;
|
||||
|
||||
// Called when a buffer encounters an error
|
||||
virtual void BufferError(std::string in_error __attribute__((unused))) { }
|
||||
|
||||
protected:
|
||||
BufferHandlerGeneric *buffer_handler;
|
||||
bool read_handler;
|
||||
bool write_handler;
|
||||
};
|
||||
|
||||
class BufferInterfaceFunc : public BufferInterface {
|
||||
public:
|
||||
BufferInterfaceFunc(std::function<void (size_t)> in_available_cb,
|
||||
std::function<void (std::string)> in_error_cb) :
|
||||
BufferInterface(),
|
||||
available_fn {in_available_cb},
|
||||
error_fn {in_error_cb} { }
|
||||
|
||||
virtual ~BufferInterfaceFunc() { }
|
||||
|
||||
virtual void BufferAvailable(size_t in_amt) {
|
||||
if (available_fn != nullptr)
|
||||
available_fn(in_amt);
|
||||
}
|
||||
|
||||
virtual void BufferError(std::string in_error) {
|
||||
if (error_fn != nullptr)
|
||||
error_fn(in_error);
|
||||
}
|
||||
|
||||
protected:
|
||||
std::function<void (size_t)> available_fn;
|
||||
std::function<void (std::string)> error_fn;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,822 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __CAPTURE_FRAMEWORK_H__
|
||||
#define __CAPTURE_FRAMEWORK_H__
|
||||
|
||||
/* A simple pure-c implementation of a datasource handler.
|
||||
*
|
||||
* This should provide a simple way to implement pure-c capture binaries with
|
||||
* a minimum of code duplication.
|
||||
*
|
||||
* This uses the simple datasource protocol to communicate over IPC or TCP,
|
||||
* and a basic ringbuffer to allocate the data.
|
||||
*
|
||||
* In this model, the actual data capture happens asynchronously in a capture
|
||||
* thread, while the protocol IO and incoming commands are handled by the
|
||||
* thread which calls the cf_handler_loop(..) function.
|
||||
*
|
||||
* Capture may be completely blocking - for example using pcap_loop directly -
|
||||
* because it is isolated from the protocol control thread.
|
||||
*/
|
||||
|
||||
#include <getopt.h>
|
||||
#include <pthread.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
/* According to POSIX.1-2001, POSIX.1-2008 */
|
||||
#include <sys/select.h>
|
||||
|
||||
/* According to earlier standards */
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "simple_ringbuf_c.h"
|
||||
|
||||
#include "protobuf_c/kismet.pb-c.h"
|
||||
#include "protobuf_c/datasource.pb-c.h"
|
||||
|
||||
struct kis_capture_handler;
|
||||
typedef struct kis_capture_handler kis_capture_handler_t;
|
||||
|
||||
struct cf_params_interface;
|
||||
typedef struct cf_params_interface cf_params_interface_t;
|
||||
|
||||
struct cf_params_list_interface;
|
||||
typedef struct cf_params_list_interface cf_params_list_interface_t;
|
||||
|
||||
struct cf_params_spectrum;
|
||||
typedef struct cf_params_spectrum cf_params_spectrum_t;
|
||||
|
||||
|
||||
/* List devices callback
|
||||
* Called to list devices available
|
||||
*
|
||||
* *msg is allocated by the framework and can hold STATUS_MAX characters and should
|
||||
* be populated with any message the listcb wants to return.
|
||||
* **interfaces mut be allocated by the list cb and should contain valid
|
||||
* list_iterface_t objects
|
||||
*
|
||||
* Return values:
|
||||
* -1 error occurred while listing
|
||||
* 0 no error occurred but no interfaces found
|
||||
* 1+ number of interfaces present in *interfaces
|
||||
*/
|
||||
typedef int (*cf_callback_listdevices)(kis_capture_handler_t *, uint32_t seqno,
|
||||
char *msg, cf_params_list_interface_t ***interfaces);
|
||||
|
||||
/* Probe definition callback
|
||||
* Called to determine if definition is supported by this datasource; the complete command
|
||||
* is passed to the datasource in case a future custom definition needs access to data
|
||||
* stored there.
|
||||
*
|
||||
* *msg is allocated by the framework and can hold STATUS_MAX characters and should
|
||||
* be populated with any message the listcb wants to return.
|
||||
*
|
||||
* **ret_interface and **ret_spectrum are to be allocated by the callback
|
||||
* function if the results are populated.
|
||||
*
|
||||
* **uuid should be allocated by the callback if it is populated during
|
||||
* probing of the device.
|
||||
*
|
||||
* Return values:
|
||||
* -1 error occurred while probing
|
||||
* 0 no error occurred, interface is not supported
|
||||
* 1 interface supported
|
||||
*/
|
||||
typedef int (*cf_callback_probe)(kis_capture_handler_t *, uint32_t seqno,
|
||||
char *definition, char *msg, char **uuid, KismetExternal__Command *command,
|
||||
cf_params_interface_t **ret_interface,
|
||||
cf_params_spectrum_t **ret_spectrum);
|
||||
|
||||
/* Open callback
|
||||
* Called to open a datasource
|
||||
*
|
||||
* *msg is allocated by the framework and can hold STATUS_MAX characters and should
|
||||
* be populated with any message the listcb wants to return
|
||||
*
|
||||
* *dlt is allocated by the framework, and should be filled with the interface DLT
|
||||
* or link type (typically from pcap_get_linktype or a known fixed value);
|
||||
*
|
||||
* **uuid is to be allocated by the cb and should hold the interface UUID
|
||||
*
|
||||
* **ret_interface and **ret_spectrum are to be allocated by the callback function
|
||||
* if the results are populated. They will be freed by the framework.
|
||||
*
|
||||
* Return values:
|
||||
* -1 error occurred while opening
|
||||
* 0 success
|
||||
*/
|
||||
typedef int (*cf_callback_open)(kis_capture_handler_t *, uint32_t seqno,
|
||||
char *definition, char *msg, uint32_t *dlt, char **uuid,
|
||||
KismetExternal__Command *command, cf_params_interface_t **ret_interface,
|
||||
cf_params_spectrum_t **ret_spectrum);
|
||||
|
||||
/* Channel translate
|
||||
* Called to translate a channel from a generic string to a local representation
|
||||
* suitable for controlling a capture interface. This is used to prevent
|
||||
* constant heavy parsing of strings during channel hopping, etc.
|
||||
*
|
||||
* The callback should allocate a custom structure containing the information and
|
||||
* return it as a void*. This structure will be passed to future callback operations.
|
||||
*
|
||||
* If the structure is complex and cannot be freed with a simple free() operation,
|
||||
* the datasource binary must provide cf_callback_chanfree.
|
||||
*
|
||||
* Returns:
|
||||
* NULL Unable to translate channel
|
||||
* Pointer callback-allocated structure containing the channel info.
|
||||
*/
|
||||
typedef void *(*cf_callback_chantranslate)(kis_capture_handler_t *, char *chanstr);
|
||||
|
||||
/* Channel set
|
||||
* Actually set a physical channel on an interface.
|
||||
*
|
||||
* Called as part of a channel hopping pattern (seqno == 0) or in response to a
|
||||
* direct channel set command (seqno != 0).
|
||||
*
|
||||
* Appropriate classification of tuning errors is left to the discretion of the
|
||||
* callback; typically an error during hopping may be allowable while an error
|
||||
* during an explicit channel set is not.
|
||||
*
|
||||
* msg is allocated by the framework and can hold up to STATUS_MAX characters. It
|
||||
* will be transmitted along with success or failure if seqno != 0.
|
||||
*
|
||||
* In all other situations, the callback may communicate to the user status
|
||||
* changes via cf_send_message(...)
|
||||
*
|
||||
* Returns:
|
||||
* -1 Fatal error occurred
|
||||
* 0 Unable to tune to this channel, exclude it from future channel hopping
|
||||
* attempts
|
||||
* 1+ Success
|
||||
*/
|
||||
typedef int (*cf_callback_chancontrol)(kis_capture_handler_t *, uint32_t seqno,
|
||||
void *privchan, char *msg);
|
||||
|
||||
/* Channel free
|
||||
* Called to free an allocated private channel struct.
|
||||
*
|
||||
* This callback is needed only when the private channel structure defined by the
|
||||
* datasource cannot be deallocated with a simple free()
|
||||
*/
|
||||
typedef void (*cf_callback_chanfree)(void *);
|
||||
|
||||
/* Unknown frame callback
|
||||
* Called when an unknown frame is received on the protocol
|
||||
*
|
||||
* This callback is only needed to handle custom frames. This allows a capture
|
||||
* handler to define its own custom frames and receive them from the comms later.
|
||||
*
|
||||
* Returns:
|
||||
* -1 Error occurred, close source
|
||||
* 0 Success, or frame ignored
|
||||
*/
|
||||
typedef int (*cf_callback_unknown)(kis_capture_handler_t *, uint32_t,
|
||||
KismetExternal__Command *);
|
||||
|
||||
/* Capture callback
|
||||
* Called inside the capture thread as the primary capture mechanism for the source.
|
||||
*
|
||||
* This callback should loop as long as the source is running, and will be placed
|
||||
* in its own thread. This callback may block, and does not need to be aware of
|
||||
* other network IO.
|
||||
*
|
||||
* This callback should perform locking on the handler_lock mutexes if changing
|
||||
* data in the handler.
|
||||
*
|
||||
* Returns:
|
||||
* On returning, the capture thread is cancelled and the source is closed.
|
||||
*/
|
||||
typedef void (*cf_callback_capture)(kis_capture_handler_t *);
|
||||
|
||||
/* Spectrum configure callback
|
||||
* Configures the basic parameters of a spectrum-capable device
|
||||
*
|
||||
* Called in response to a SPECSET block in a CONFIGURE command
|
||||
*
|
||||
* msg is allocated by the framework and can hold up to STATUS_MAX characters. It
|
||||
* will be transmitted along with the success or failure value if seqno != 0
|
||||
*
|
||||
* In all other situations, the callback may communicate status to the user
|
||||
* via cf_send_message(...)
|
||||
*
|
||||
* Returns:
|
||||
* -1 Error occurred
|
||||
* 0 Success
|
||||
*/
|
||||
typedef int (*cf_callback_spectrumconfig)(kis_capture_handler_t *, uint32_t seqno,
|
||||
uint64_t start_mhz, uint64_t end_mhz, uint64_t num_per_freq, uint64_t bin_width,
|
||||
unsigned int amp, uint64_t if_amp, uint64_t baseband_amp,
|
||||
KismetExternal__Command *command);
|
||||
|
||||
struct kis_capture_handler {
|
||||
/* Capture source type */
|
||||
char *capsource_type;
|
||||
|
||||
/* Does this driver support remote capture? Most should, and it defaults to
|
||||
* true. */
|
||||
int remote_capable;
|
||||
|
||||
/* Last time we got a ping */
|
||||
time_t last_ping;
|
||||
|
||||
/* Sequence number counter */
|
||||
uint32_t seqno;
|
||||
|
||||
/* Descriptor pair */
|
||||
int in_fd;
|
||||
int out_fd;
|
||||
|
||||
/* Remote host and port if acting as a remote drone */
|
||||
char *remote_host;
|
||||
unsigned int remote_port;
|
||||
|
||||
/* Specified commandline source, used for remote cap */
|
||||
char *cli_sourcedef;
|
||||
|
||||
/* Retry remote connections */
|
||||
int remote_retry;
|
||||
|
||||
/* Kick into daemon mode for remote connections */
|
||||
int daemonize;
|
||||
|
||||
/* TCP connection */
|
||||
int tcp_fd;
|
||||
|
||||
/* Die when we hit the end of our write buffer */
|
||||
int spindown;
|
||||
|
||||
/* Buffers */
|
||||
kis_simple_ringbuf_t *in_ringbuf;
|
||||
kis_simple_ringbuf_t *out_ringbuf;
|
||||
|
||||
/* Lock for output buffer */
|
||||
pthread_mutex_t out_ringbuf_lock;
|
||||
|
||||
/* conditional waiter for ringbuf flushing data */
|
||||
pthread_cond_t out_ringbuf_flush_cond;
|
||||
pthread_mutex_t out_ringbuf_flush_cond_mutex;
|
||||
|
||||
/* Are we shutting down? */
|
||||
int shutdown;
|
||||
pthread_mutex_t handler_lock;
|
||||
|
||||
/* Callbacks called for various incoming packets */
|
||||
cf_callback_listdevices listdevices_cb;
|
||||
cf_callback_probe probe_cb;
|
||||
cf_callback_open open_cb;
|
||||
|
||||
cf_callback_chantranslate chantranslate_cb;
|
||||
cf_callback_chancontrol chancontrol_cb;
|
||||
cf_callback_chanfree chanfree_cb;
|
||||
|
||||
cf_callback_unknown unknown_cb;
|
||||
|
||||
cf_callback_capture capture_cb;
|
||||
|
||||
cf_callback_spectrumconfig spectrumconfig_cb;
|
||||
|
||||
|
||||
/* Arbitrary data blob */
|
||||
void *userdata;
|
||||
|
||||
/* Capture thread */
|
||||
int capture_running;
|
||||
pthread_t capturethread;
|
||||
|
||||
/* Non-hopping channel */
|
||||
char *channel;
|
||||
|
||||
/* Hopping thread */
|
||||
int hopping_running;
|
||||
pthread_t hopthread;
|
||||
|
||||
/* Hop information: Original channel list, custom converted hop list (which
|
||||
* MUST be the same length as channel hop list; if a channel cannot be parsed,
|
||||
* put a NULL), hop list size, and rate. */
|
||||
char **channel_hop_list;
|
||||
void **custom_channel_hop_list;
|
||||
size_t channel_hop_list_sz;
|
||||
double channel_hop_rate;
|
||||
|
||||
/* Linked list of failed channel sets so we can flush the channel array out */
|
||||
void *channel_hop_failure_list;
|
||||
size_t channel_hop_failure_list_sz;
|
||||
|
||||
/* Do we shuffle? Do we have a shuffle spacing from the driver? */
|
||||
int channel_hop_shuffle;
|
||||
unsigned int channel_hop_shuffle_spacing;
|
||||
|
||||
int channel_hop_offset;
|
||||
|
||||
/* Fixed GPS location from command line */
|
||||
double gps_fixed_lat, gps_fixed_lon, gps_fixed_alt;
|
||||
|
||||
/* Fixed GPS name */
|
||||
char *gps_name;
|
||||
};
|
||||
|
||||
|
||||
struct cf_params_interface {
|
||||
char *capif;
|
||||
char *chanset;
|
||||
char **channels;
|
||||
size_t channels_len;
|
||||
char *hardware;
|
||||
};
|
||||
|
||||
struct cf_params_list_interface {
|
||||
char *interface;
|
||||
char *flags;
|
||||
char *hardware;
|
||||
};
|
||||
|
||||
struct cf_params_spectrum {
|
||||
uint64_t start_mhz;
|
||||
uint64_t end_mhz;
|
||||
uint64_t samples_per_freq;
|
||||
uint64_t bin_width;
|
||||
uint8_t amp;
|
||||
uint64_t if_amp;
|
||||
uint64_t baseband_amp;
|
||||
};
|
||||
|
||||
/* Exceedingly simple linked list structure for errors setting channels
|
||||
* so we can screen them out */
|
||||
struct cf_channel_error {
|
||||
unsigned long channel_pos;
|
||||
struct cf_channel_error *next;
|
||||
};
|
||||
|
||||
/* Set remote capability flags.
|
||||
* Most sources should support remote capture as nearly no extra work is required,
|
||||
* however sources which for some reason cannot can set the flag to 0.
|
||||
*
|
||||
*/
|
||||
void cf_set_remote_capable(kis_capture_handler_t *caph, int in_capable);
|
||||
|
||||
/* Parse an interface name from a definition string.
|
||||
* Returns a pointer to the start of the interface name in the definition in
|
||||
* ret_interface, and the length of the interface name.
|
||||
*
|
||||
* CALLERS SHOULD ALLOCATE AN ADDITIONAL BYTE FOR NULL TERMINATION when extracting
|
||||
* this string, the LENGTH RETURNED IS THE ABSOLUTE LENGTH INSIDE THE DEFINITION.
|
||||
*
|
||||
* Returns:
|
||||
* -1 Error
|
||||
* 1+ Length of interface name in the definition
|
||||
*/
|
||||
int cf_parse_interface(char **ret_interface, char *definition);
|
||||
|
||||
/* Parse a definition string looking for a specific flag and returns a pointer to
|
||||
* the start of the flag value in definition in ret_value, and the length of the
|
||||
* flag.
|
||||
*
|
||||
* Parameter lists may include quoted strings; the quotes will not be returned;
|
||||
* for instance channels="1,2,3,4",foo=bar will return 1,2,3,4 for 'channels'.
|
||||
*
|
||||
* CALLERS SHOULD ALLOCATE AN ADDITIONAL BYTE FOR NULL TERMINATION when extracting
|
||||
* this string, the LENGTH RETURNED IS THE ABSOLUTE LENGTH INSIDE THE DEFINITION.
|
||||
*
|
||||
* Returns:
|
||||
* -1 Error
|
||||
* 0 Flag not found
|
||||
* 1+ Length of flag value in definition
|
||||
*/
|
||||
int cf_find_flag(char **ret_value, const char *flag, char *definition);
|
||||
|
||||
/* Parse a comma separated list of strings, such as channels, into an array of char*.
|
||||
*
|
||||
* Expects the size of the incoming string in in_sz, allowing for direct passing
|
||||
* of values extracted via cf_find_flag which are not null terminated
|
||||
*
|
||||
* Parsed list is placed into *ret_splitlist and the length is placed into
|
||||
* *ret_splitlist_sz. The caller is responsible for freeing the strings and
|
||||
* the array.
|
||||
*
|
||||
* Returns:
|
||||
* -1 Error
|
||||
* 0 Success
|
||||
*/
|
||||
int cf_split_list(char *in_str, size_t in_sz, char in_split, char ***ret_splitlist,
|
||||
size_t *ret_splitlist_sz);
|
||||
|
||||
/* Merge two string arrays of strings, such as channels, into a single array of
|
||||
* unique values.
|
||||
*
|
||||
* Passed elements *are copied*. Caller is responsible for freeing original
|
||||
* copies.
|
||||
*
|
||||
* The resulting list is dynamically allocated. Caller is responsible for
|
||||
* freeing returned list after use.
|
||||
*
|
||||
* Strings are compared with a case-insensitive compare.
|
||||
*
|
||||
* Returns:
|
||||
* 0 Error / Empty lists passed
|
||||
* sz Size of *ret_list
|
||||
*/
|
||||
size_t cf_append_unique_chans(char **in_list1, size_t in_list1_sz,
|
||||
char **in_list2, size_t in_list2_sz, char ***ret_list);
|
||||
|
||||
|
||||
/* Initialize a caphandler
|
||||
*
|
||||
* Returns:
|
||||
* Pointer to handler or NULL on failure to allocate
|
||||
*/
|
||||
kis_capture_handler_t *cf_handler_init(const char *in_type);
|
||||
|
||||
/* Destroy a caphandler
|
||||
*
|
||||
* Closes any sockets/descriptors and destroys ringbuffers
|
||||
*/
|
||||
void cf_handler_free(kis_capture_handler_t *caph);
|
||||
|
||||
|
||||
/* Initialize an interface param
|
||||
*
|
||||
* Returns:
|
||||
* Pointer to interface parameter struct or NULL
|
||||
*/
|
||||
cf_params_interface_t *cf_params_interface_new();
|
||||
|
||||
/* Destroy an interface parameter and it's internal fields */
|
||||
void cf_params_interface_free(cf_params_interface_t *pi);
|
||||
|
||||
/* Initialize a spectrum param
|
||||
*
|
||||
* Returns:
|
||||
* Pointer to spectrum parameter struct or NULL
|
||||
*/
|
||||
cf_params_spectrum_t *cf_params_spectrum_new();
|
||||
|
||||
/* Destroy an interface parameter and it's internal fields */
|
||||
void cf_params_spectrum_free(cf_params_spectrum_t *si);
|
||||
|
||||
|
||||
/* Shutdown immediately - dies at the start of the next select() loop, regardless
|
||||
* of pending data.
|
||||
*
|
||||
* It is not safe to destroy the capture_handler record until the select() blocking
|
||||
* loop has exited.
|
||||
*/
|
||||
void cf_handler_shutdown(kis_capture_handler_t *caph);
|
||||
|
||||
/* Spindown gracefully - flushes any pending data in the write buffer and then
|
||||
* exits the select() loop.
|
||||
*
|
||||
* It is not safe to destroy the capture_handler record until the select() blocking
|
||||
* loop has exited.
|
||||
*/
|
||||
void cf_handler_spindown(kis_capture_handler_t *caph);
|
||||
|
||||
/* Pivot into a new namespace and remount root as read-only - this should be
|
||||
* used whenever possible by data sources on Linux which can be installed as suidroot;
|
||||
* this pivots into a new namespace and remounts root as readonly.
|
||||
*
|
||||
* Returns
|
||||
* -1 Error pivoting into restricted namespace
|
||||
* 0 Not compiled on Linux
|
||||
* 1 Success
|
||||
*/
|
||||
int cf_jail_filesystem(kis_capture_handler_t *caph);
|
||||
|
||||
/* Drop most root capabilities - this should be used whenever possible by data
|
||||
* sources which can be installed as suidroot; this removes all capabilities except
|
||||
* NET_ADMIN and NET_RAW.
|
||||
*
|
||||
* Returns:
|
||||
* -1 Error dropping capabilities
|
||||
* 0 Capability support not compiled in
|
||||
* 1 Success
|
||||
*/
|
||||
int cf_drop_most_caps(kis_capture_handler_t *caph);
|
||||
|
||||
/* Assign a channel hopping list processed by a capture binary */
|
||||
void cf_handler_assign_hop_channels(kis_capture_handler_t *caph, char **stringchans,
|
||||
void **privchans, size_t chan_sz, double rate, int shuffle, int shuffle_spacing,
|
||||
int offset);
|
||||
|
||||
/* Set a channel hop shuffle spacing */
|
||||
void cf_handler_set_hop_shuffle_spacing(kis_capture_handler_t *capf, int spacing);
|
||||
|
||||
|
||||
/* Parse command line options
|
||||
*
|
||||
* Parse command line for --in-fd, --out-fd, --connect, --source, and populate.
|
||||
*
|
||||
* Returns:
|
||||
* -1 Missing in-fd/out-fd or --connect, or unknown argument, caller should print
|
||||
* help and exit
|
||||
* 1 Success, using interproc IPC
|
||||
* 2 Success, using TCP remote connection
|
||||
*/
|
||||
int cf_handler_parse_opts(kis_capture_handler_t *caph, int argc, char *argv[]);
|
||||
|
||||
/* Print the standard help header */
|
||||
void cf_print_help(kis_capture_handler_t *caph, const char *argv0);
|
||||
|
||||
/* Set callbacks; pass NULL to remove a callback. */
|
||||
void cf_handler_set_listdevices_cb(kis_capture_handler_t *capf,
|
||||
cf_callback_listdevices cb);
|
||||
void cf_handler_set_probe_cb(kis_capture_handler_t *capf, cf_callback_probe cb);
|
||||
void cf_handler_set_open_cb(kis_capture_handler_t *capf, cf_callback_open cb);
|
||||
|
||||
void cf_handler_set_chantranslate_cb(kis_capture_handler_t *capf,
|
||||
cf_callback_chantranslate cb);
|
||||
void cf_handler_set_chancontrol_cb(kis_capture_handler_t *capf,
|
||||
cf_callback_chancontrol cb);
|
||||
void cf_handler_set_chanfree_cb(kis_capture_handler_t *capf, cf_callback_chanfree cb);
|
||||
|
||||
void cf_handler_set_spectrumconfig_cb(kis_capture_handler_t *capf,
|
||||
cf_callback_spectrumconfig cb);
|
||||
|
||||
void cf_handler_set_unknown_cb(kis_capture_handler_t *capf, cf_callback_unknown cb);
|
||||
|
||||
/* Set the capture function, which runs inside its own thread */
|
||||
void cf_handler_set_capture_cb(kis_capture_handler_t *capf, cf_callback_capture cb);
|
||||
|
||||
|
||||
|
||||
/* Set random data blob */
|
||||
void cf_handler_set_userdata(kis_capture_handler_t *capf, void *userdata);
|
||||
|
||||
|
||||
/* Initiate the capture thread, which will call the capture callback function in
|
||||
* its own thread */
|
||||
int cf_handler_launch_capture_thread(kis_capture_handler_t *caph);
|
||||
|
||||
/* Initiate the channel hopping thread, which will call the channel set function
|
||||
* its own thread */
|
||||
int cf_handler_launch_hopping_thread(kis_capture_handler_t *caph);
|
||||
|
||||
|
||||
/* Perform a blocking wait, waiting for the ringbuffer to free data */
|
||||
void cf_handler_wait_ringbuffer(kis_capture_handler_t *caph);
|
||||
|
||||
|
||||
/* Handle data in the rx ringbuffer; called from the select/poll loop.
|
||||
* Calls callbacks for packet types automatically when a complete packet is
|
||||
* received.
|
||||
*/
|
||||
int cf_handle_rx_data(kis_capture_handler_t *caph);
|
||||
|
||||
|
||||
/* Connect to a network socket, if remote connection is specified; this should
|
||||
* not be needed by capture tools using the framework; the capture loop will
|
||||
* be managed directly via cf_handler_remote_capture
|
||||
*
|
||||
* Returns:
|
||||
* -1 Error, could not connect, process should exit
|
||||
* 0 No remote connection specified
|
||||
* 1 Successful remote connection
|
||||
*/
|
||||
int cf_handler_remote_connect(kis_capture_handler_t *caph);
|
||||
|
||||
/* Set up a fork loop for remote capture processes. The normal capture code
|
||||
* is run in an independently executed process, allowing for one-shot privilege
|
||||
* dropping and eliminating potential memory leaks from interfering with reloading
|
||||
* the capture process.
|
||||
*
|
||||
* Capture drivers should call this after configuring callbacks and parsing options,
|
||||
* but before dropping privileges, setting up any unique state inside the main loop,
|
||||
* or running cf_handler_loop.
|
||||
*/
|
||||
void cf_handler_remote_capture(kis_capture_handler_t *caph);
|
||||
|
||||
/* Handle the sockets in a select() loop; this function will block until it
|
||||
* encounters an error or gets a shutdown command.
|
||||
*
|
||||
* Capture drivers should typically define their IO in a callback which will
|
||||
* be run in a thread automatically via cf_handler_set_capture_cb.
|
||||
* cf_handler_loop() should be called in the main() function.
|
||||
*
|
||||
* Returns:
|
||||
* -1 Error, process should exit
|
||||
* 0 No error, process should wait to be killed
|
||||
*/
|
||||
int cf_handler_loop(kis_capture_handler_t *caph);
|
||||
|
||||
/* Send a blob of data. This must be a formatted packet created by one of the
|
||||
* other functions.
|
||||
*
|
||||
* May be called from any thread.
|
||||
*
|
||||
* Returns:
|
||||
* -1 An error occurred
|
||||
* 0 Insufficient space in buffer
|
||||
* 1 Success
|
||||
*/
|
||||
int cf_send_raw_bytes(kis_capture_handler_t *caph, uint8_t *data, size_t len);
|
||||
|
||||
/* Wrap a sub-packet into a KismetExternal__Command, frame it, and send it.
|
||||
* May be called from any thread.
|
||||
*
|
||||
* The supplied data buffer will be put into the command payload.
|
||||
*
|
||||
* The supplied data WILL BE FREED regardless of the success of transmitting
|
||||
* the packet.
|
||||
*
|
||||
* Returns:
|
||||
* -1 An error occurred
|
||||
* 0 Insufficient space in buffer
|
||||
* 1 Success
|
||||
*/
|
||||
int cf_send_packet(kis_capture_handler_t *caph, const char *packtype,
|
||||
uint8_t *data, size_t len);
|
||||
|
||||
/* Send a MESSAGE
|
||||
* Can be called from any thread.
|
||||
*
|
||||
* Flags are expected to match the MSGFLAG_ flags in simple_datasource.h
|
||||
*
|
||||
* Returns:
|
||||
* -1 An error occurred writing the frame
|
||||
* 0 Insufficient space in buffer
|
||||
* 1 Success
|
||||
*/
|
||||
int cf_send_message(kis_capture_handler_t *caph, const char *message,
|
||||
unsigned int flags);
|
||||
|
||||
/* Send a MESSAGE+WARNING
|
||||
* Can be called from any thread.
|
||||
*
|
||||
* Flags are expected to match the MSGFLAG_ flags in simple_datasource.h
|
||||
* Additionally a WARNING message may be attached which will be stored in the
|
||||
* source warning field
|
||||
*
|
||||
* Returns:
|
||||
* -1 An error occurred writing the frame
|
||||
* 0 Insufficient space in buffer
|
||||
* 1 Success
|
||||
*/
|
||||
int cf_send_warning(kis_capture_handler_t *caph, const char *warning);
|
||||
|
||||
/* Send an ERROR
|
||||
* Can be called from any thread
|
||||
*
|
||||
* Send an error message indicating this source is now closed
|
||||
*
|
||||
* Returns:
|
||||
* -1 An error occurred writing the frame
|
||||
* 0 Insufficient space in buffer
|
||||
* 1 Success
|
||||
*/
|
||||
int cf_send_error(kis_capture_handler_t *caph, uint32_t in_seqno, const char *message);
|
||||
|
||||
/* Send a LISTRESP response
|
||||
* Can be called from any thread.
|
||||
*
|
||||
* interfaces and flags are expected to be of equal lengths: if there are no
|
||||
* corresponding flags for an interface, a NULL should be placed in that slot.
|
||||
*
|
||||
* Returns:
|
||||
* -1 An error occurred writing the frame
|
||||
* 0 Insufficient space in buffer
|
||||
* 1 Success
|
||||
*/
|
||||
int cf_send_listresp(kis_capture_handler_t *caph, uint32_t seq, unsigned int success,
|
||||
const char *msg, cf_params_list_interface_t **interfaces, size_t len);
|
||||
|
||||
/* Send a PROBERESP response; can contain traditional interface data, spectrum interface
|
||||
* data, both, or neither in the case of an error.
|
||||
*
|
||||
* Can be called from any thread
|
||||
*
|
||||
* Returns:
|
||||
* -1 An error occurred while creating the packet
|
||||
* 0 Insufficient space in buffer
|
||||
* 1 Success
|
||||
*/
|
||||
int cf_send_proberesp(kis_capture_handler_t *caph, uint32_t seq, unsigned int success,
|
||||
const char *msg, cf_params_interface_t *interface, cf_params_spectrum_t *spectrum);
|
||||
|
||||
/* Send an OPENRESP response
|
||||
* Can be called from any thread
|
||||
*
|
||||
* To send supported channels list, provide channels and channels_len, otherwise set
|
||||
* channels_len to 0
|
||||
*
|
||||
* Returns:
|
||||
* -1 An error occurred while creating the packet
|
||||
* 0 Insufficient space in buffer
|
||||
* 1 Success
|
||||
*/
|
||||
int cf_send_openresp(kis_capture_handler_t *caph, uint32_t seq, unsigned int success,
|
||||
const char *msg, const uint32_t dlt, const char *uuid,
|
||||
cf_params_interface_t *interface, cf_params_spectrum_t *spectrum);
|
||||
|
||||
/* Send a DATA frame with packet data
|
||||
* Can be called from any thread
|
||||
*
|
||||
* If present, include message_kv, signal_kv, or gps_kv along with the packet data.
|
||||
*
|
||||
* Returns:
|
||||
* -1 An error occurred
|
||||
* 0 Insufficient space in buffer
|
||||
* 1 Success
|
||||
*/
|
||||
int cf_send_data(kis_capture_handler_t *caph,
|
||||
KismetExternal__MsgbusMessage *kv_message,
|
||||
KismetDatasource__SubSignal *kv_signal,
|
||||
KismetDatasource__SubGps *kv_gps,
|
||||
struct timeval ts, uint32_t dlt, uint32_t packet_sz, uint8_t *pack);
|
||||
|
||||
/* Send a DATA frame with JSON non-packet data
|
||||
* Can be called from any thread
|
||||
*
|
||||
* If present, include message_kv, signal_kv, or gps_kv along with the json data.
|
||||
*
|
||||
* Returns:
|
||||
* -1 An error occured
|
||||
* 0 Insufficient space in buffer, try again
|
||||
* 1 Success
|
||||
*/
|
||||
int cf_send_json(kis_capture_handler_t *caph,
|
||||
KismetExternal__MsgbusMessage *kv_message,
|
||||
KismetDatasource__SubSignal *kv_signal,
|
||||
KismetDatasource__SubGps *kv_gps,
|
||||
struct timeval ts, char *type, char *json);
|
||||
|
||||
/* Send a CONFIGRESP with only a success and optional message
|
||||
*
|
||||
* Returns:
|
||||
* -1 An error occurred
|
||||
* 0 Insufficient space in buffer
|
||||
* 1 Success
|
||||
*/
|
||||
int cf_send_configresp(kis_capture_handler_t *caph, unsigned int seq,
|
||||
unsigned int success, const char *msg, const char *warning);
|
||||
|
||||
/* Send a PING request
|
||||
*
|
||||
* Returns:
|
||||
* -1 An error occurred
|
||||
* 0 Insufficient space in buffer
|
||||
* 1 Success
|
||||
*/
|
||||
int cf_send_ping(kis_capture_handler_t *caph);
|
||||
|
||||
/* Send a PONG response
|
||||
*
|
||||
* Returns:
|
||||
* -1 An error occurred
|
||||
* 0 Insufficient space in buffer
|
||||
* 1 Success
|
||||
*/
|
||||
int cf_send_pong(kis_capture_handler_t *caph, uint32_t in_seqno);
|
||||
|
||||
/* Send a NEWSOURCE command to initiate connecting to a remote server
|
||||
*
|
||||
* Returns:
|
||||
* -1 An error occurred
|
||||
* 0 Insufficient space in buffer
|
||||
* 1 Success
|
||||
*/
|
||||
int cf_send_newsource(kis_capture_handler_t *caph, const char *uuid);
|
||||
|
||||
/* Simple frequency parser, returns the frequency in khz from multiple input
|
||||
* formats, such as:
|
||||
* 123KHz
|
||||
* 123000Hz
|
||||
* 1.23MHz
|
||||
* 1.23e5KHz
|
||||
*/
|
||||
double cf_parse_frequency(const char *freq);
|
||||
|
||||
/* Simple redefinition of message flags */
|
||||
#define MSGFLAG_DEBUG KISMET_EXTERNAL__MSGBUS_MESSAGE__MESSAGE_TYPE__DEBUG
|
||||
#define MSGFLAG_INFO KISMET_EXTERNAL__MSGBUS_MESSAGE__MESSAGE_TYPE__INFO
|
||||
#define MSGFLAG_ERROR KISMET_EXTERNAL__MSGBUS_MESSAGE__MESSAGE_TYPE__ERROR
|
||||
#define MSGFLAG_ALERT KISMET_EXTERNAL__MSGBUS_MESSAGE__MESSAGE_TYPE__ALERT
|
||||
#define MSGFLAG_FATAL KISMET_EXTERNAL__MSGBUS_MESSAGE__MESSAGE_TYPE__FATAL
|
||||
|
||||
uint32_t adler32_partial_csum(uint8_t *in_buf, size_t in_len,
|
||||
uint32_t *s1, uint32_t *s2);
|
||||
uint32_t adler32_csum(uint8_t *in_buf, size_t in_len);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,527 +0,0 @@
|
|||
"""
|
||||
freaklabs zigbee sniffer source
|
||||
|
||||
(c) 2018 Mike Kershaw / Dragorn
|
||||
Licensed under GPL2 or above
|
||||
|
||||
accepts standard source hop options
|
||||
accepts additional options:
|
||||
|
||||
device=/path/to/serial
|
||||
baud=baudrate
|
||||
band=800|900|2400
|
||||
|
||||
Based in part on the Sensniff code from:
|
||||
https://github.com/freaklabs/sensniff-freaklabs.git
|
||||
|
||||
Under the following license:
|
||||
|
||||
Copyright (c) 2012, George Oikonomou (oikonomou@users.sf.net)
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the owner nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""
|
||||
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
import json
|
||||
import os
|
||||
|
||||
try:
|
||||
import serial
|
||||
except ImportError:
|
||||
raise ImportError("KismetCaptureFreaklabsZigbee requires python-serial, please install it!")
|
||||
|
||||
import struct
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import uuid
|
||||
|
||||
from . import kismetexternal
|
||||
|
||||
LINKTYPE_IEEE802_15_4_NOFCS = 230
|
||||
LINKTYPE_IEEE802_15_4 = 195
|
||||
NETWORK = LINKTYPE_IEEE802_15_4_NOFCS
|
||||
|
||||
CMD_FRAME = 0x00
|
||||
CMD_CHANNEL = 0x01
|
||||
CMD_GET_CHANNEL = 0x81
|
||||
CMD_SET_CHANNEL = 0x82
|
||||
SNIFFER_PROTO_VERSION = 1
|
||||
|
||||
class FreaklabException(Exception):
|
||||
pass
|
||||
|
||||
class SerialInputHandler(object):
|
||||
def __init__(self, port, baudrate):
|
||||
self.__sensniff_magic_legacy = struct.pack('BBBB', 0x53, 0x6E, 0x69, 0x66)
|
||||
self.__sensniff_magic = struct.pack('BBBB', 0xC1, 0x1F, 0xFE, 0x72)
|
||||
self._current_channel = -1
|
||||
|
||||
try:
|
||||
self.port = serial.Serial(port = port,
|
||||
baudrate = baudrate,
|
||||
bytesize = serial.EIGHTBITS,
|
||||
parity = serial.PARITY_NONE,
|
||||
stopbits = serial.STOPBITS_ONE,
|
||||
xonxoff = False,
|
||||
rtscts = False,
|
||||
timeout = 0.1)
|
||||
self.port.flushInput()
|
||||
self.port.flushOutput()
|
||||
except (serial.SerialException, ValueError, IOError, OSError) as e:
|
||||
raise FreaklabException("Could not open freaklabs device: {}".format(e))
|
||||
|
||||
def read_frame(self):
|
||||
try:
|
||||
# Read the magic + 1 more byte
|
||||
b = self.port.read(5)
|
||||
size = len(b)
|
||||
except (IOError, OSError) as e:
|
||||
raise FreaklabException("Error reading port: {}".format(e))
|
||||
|
||||
if size == 0:
|
||||
return b
|
||||
if size < 5:
|
||||
self.port.flushInput()
|
||||
return ''
|
||||
|
||||
if b[0:4] not in (self.__sensniff_magic, self.__sensniff_magic_legacy):
|
||||
# Peripheral UART output - print it
|
||||
per_out = self.port.readline().rstrip()
|
||||
return ''
|
||||
|
||||
# If we reach here:
|
||||
# Next byte == 1: Proto version 1, header follows
|
||||
# Next Byte != 1 && < 128. Old proto version. Frame follows, length == the byte
|
||||
b = bytearray(b)
|
||||
if b[4] != SNIFFER_PROTO_VERSION:
|
||||
# Legacy contiki sniffer support. Will slowly fade away
|
||||
size = b[4]
|
||||
try:
|
||||
b = self.port.read(size)
|
||||
except (IOError, OSError) as e:
|
||||
raise FreaklabException("Error reading port: {}".format(e))
|
||||
return
|
||||
|
||||
if len(b) != size:
|
||||
# We got the magic right but subsequent bytes did not match
|
||||
# what we expected to receive
|
||||
self.port.flushInput()
|
||||
return ''
|
||||
|
||||
return b
|
||||
|
||||
# If we reach here, we have a packet of proto ver SNIFFER_PROTO_VERSION
|
||||
# Read CMD and LEN
|
||||
try:
|
||||
b = self.port.read(2)
|
||||
|
||||
except (IOError, OSError) as e:
|
||||
raise FreaklabException("Error reading port: {}".format(e))
|
||||
return
|
||||
|
||||
if size < 2:
|
||||
self.port.flushInput()
|
||||
return ''
|
||||
|
||||
b = bytearray(b)
|
||||
cmd = b[0]
|
||||
length = b[1]
|
||||
|
||||
# Read the frame or command response
|
||||
b = self.port.read(length)
|
||||
if len(b) != length:
|
||||
# We got the magic right but subsequent bytes did not match
|
||||
# what we expected to receive
|
||||
self.port.flushInput()
|
||||
return ''
|
||||
|
||||
# If we reach here, b holds a frame or a command response of length len
|
||||
if cmd == CMD_FRAME:
|
||||
return b
|
||||
|
||||
# If we reach here, we have a command response
|
||||
b = bytearray(b)
|
||||
if cmd == CMD_CHANNEL:
|
||||
self._current_channel = b[0]
|
||||
return ''
|
||||
|
||||
def __write_command(self, cmd):
|
||||
self.port.write(self.__sensniff_magic)
|
||||
self.port.write(bytearray([SNIFFER_PROTO_VERSION]))
|
||||
self.port.write(cmd)
|
||||
self.port.flush()
|
||||
|
||||
def set_channel(self, channel):
|
||||
self.__write_command(bytearray([CMD_SET_CHANNEL, 1, channel]))
|
||||
# this hardware takes 150us for PLL lock and we need enough time to read the success message
|
||||
time.sleep (0.003)
|
||||
if (channel != self._current_channel):
|
||||
raise FreaklabException
|
||||
|
||||
def get_channel(self):
|
||||
self.__write_command(bytearray([CMD_GET_CHANNEL]))
|
||||
|
||||
class KismetFreaklabsZigbee(object):
|
||||
def __init__(self):
|
||||
# Frequency map
|
||||
self.frequencies = {
|
||||
0: 868,
|
||||
1: 906,
|
||||
2: 908,
|
||||
3: 910,
|
||||
4: 912,
|
||||
5: 914,
|
||||
6: 916,
|
||||
7: 918,
|
||||
8: 920,
|
||||
9: 922,
|
||||
10: 924,
|
||||
11: 2405,
|
||||
12: 2410,
|
||||
13: 2415,
|
||||
14: 2420,
|
||||
15: 2425,
|
||||
16: 2430,
|
||||
17: 2435,
|
||||
18: 2440,
|
||||
19: 2445,
|
||||
20: 2450,
|
||||
21: 2455,
|
||||
22: 2460,
|
||||
23: 2465,
|
||||
24: 2470,
|
||||
25: 2475,
|
||||
26: 2480
|
||||
}
|
||||
|
||||
self.band_map = {}
|
||||
self.band_map["800"] = ["0"]
|
||||
self.band_map["900"] = []
|
||||
self.band_map["2400"] = []
|
||||
# Freaklabs 900mhz hw can operate down to channel 0, include it in the list
|
||||
for c in range(0, 11):
|
||||
self.band_map["900"].append("{}".format(c))
|
||||
for c in range(11, 27):
|
||||
self.band_map["2400"].append("{}".format(c))
|
||||
|
||||
self.defaults = {}
|
||||
|
||||
self.defaults['device'] = "/dev/ttyUSB0"
|
||||
self.defaults['baudrate'] = "57600"
|
||||
self.defaults['band'] = "auto"
|
||||
self.defaults['name'] = None
|
||||
|
||||
self.hop_thread = None
|
||||
self.monitor_thread = None
|
||||
|
||||
self.chan_config_lock = threading.RLock()
|
||||
self.chan_config = {}
|
||||
self.chan_config['chan_pos'] = 0
|
||||
self.chan_config['hopping'] = True
|
||||
self.chan_config['channel'] = "0"
|
||||
self.chan_config['hop_channels'] = []
|
||||
self.chan_config['hop_rate'] = 1
|
||||
self.chan_config['chan_skip'] = 0
|
||||
self.chan_config['chan_offset'] = 0
|
||||
|
||||
self.serialhandler = None
|
||||
|
||||
parser = argparse.ArgumentParser(description='Kismet datasource to capture from Freaklabs Zigbee hardware',
|
||||
epilog='Requires Freaklabs hardware (or compatible SenSniff-based device)')
|
||||
|
||||
parser.add_argument('--in-fd', action="store", type=int, dest="infd")
|
||||
parser.add_argument('--out-fd', action="store", type=int, dest="outfd")
|
||||
parser.add_argument('--connect', action="store", dest="connect")
|
||||
parser.add_argument("--source", action="store", dest="source")
|
||||
|
||||
self.config = parser.parse_args()
|
||||
|
||||
if not self.config.connect == None and self.config.source == None:
|
||||
print("You must specify a source with --source when connecting to a remote Kismet server")
|
||||
sys.exit(0)
|
||||
|
||||
self.proberet = None
|
||||
|
||||
if not self.config.source == None:
|
||||
(source, options) = kismetexternal.Datasource.parse_definition(self.config.source)
|
||||
|
||||
if source == None:
|
||||
print("Could not parse the --source option; this should be a standard Kismet source definition.")
|
||||
sys.exit(0)
|
||||
|
||||
self.proberet = self.datasource_probesource(source, options)
|
||||
|
||||
if self.proberet == None:
|
||||
print("Could not configure local source {}, check your source options and config.")
|
||||
sys.exit(0)
|
||||
|
||||
if not "success" in self.proberet:
|
||||
print("Could not configure local source {}, check your source options and config.")
|
||||
if "message" in self.proberet:
|
||||
print(self.proberet["message"])
|
||||
sys.exit(0)
|
||||
|
||||
if not self.proberet["success"]:
|
||||
print("Could not configure local source {}, check your source options and config.")
|
||||
if "message" in self.proberet:
|
||||
print(self.proberet["message"])
|
||||
sys.exit(0)
|
||||
|
||||
print("Connecting to remote server {}".format(self.config.connect))
|
||||
|
||||
self.kismet = kismetexternal.Datasource(self.config.infd, self.config.outfd, remote = self.config.connect)
|
||||
|
||||
self.kismet.set_configsource_cb(self.datasource_configure)
|
||||
self.kismet.set_listinterfaces_cb(self.datasource_listinterfaces)
|
||||
self.kismet.set_opensource_cb(self.datasource_opensource)
|
||||
self.kismet.set_probesource_cb(self.datasource_probesource)
|
||||
|
||||
# If we're connecting remote, kick a newsource
|
||||
if self.proberet:
|
||||
print("Registering remote source {} {}".format('freaklabszigbee', self.config.source))
|
||||
self.kismet.send_datasource_newsource(self.config.source, 'freaklabszigbee', self.proberet['uuid'])
|
||||
|
||||
self.kismet.start()
|
||||
|
||||
def is_running(self):
|
||||
return self.kismet.is_running()
|
||||
|
||||
def __start_hopping(self):
|
||||
def hop_func():
|
||||
while self.chan_config['hopping']:
|
||||
wait_usec = 1.0 / self.chan_config['hop_rate']
|
||||
|
||||
try:
|
||||
self.chan_config_lock.acquire()
|
||||
c = int(self.chan_config['hop_channels'][self.chan_config['chan_pos'] % len(self.chan_config['hop_channels'])])
|
||||
self.serialhandler.set_channel(c)
|
||||
except FreaklabException as e:
|
||||
self.kismet.send_datasource_error_report(message = "Could not tune to {}: {}".format(self.chan_config['chan_pos'], e))
|
||||
finally:
|
||||
self.chan_config_lock.release()
|
||||
|
||||
self.chan_config['chan_pos'] = self.chan_config['chan_pos'] + 1
|
||||
|
||||
self.hop_thread = None
|
||||
|
||||
if self.hop_thread:
|
||||
return
|
||||
|
||||
self.hop_thread = threading.Thread(target = hop_func)
|
||||
self.hop_thread.daemon = True
|
||||
self.hop_thread.start()
|
||||
|
||||
def __detect_band(self, device):
|
||||
try:
|
||||
self.serialhandler.set_channel(2)
|
||||
self.kismet.send_message("Found band \'900MHz\' for freaklabs source on \'{}\'".format(device))
|
||||
return "900"
|
||||
except FreaklabException as e:
|
||||
True
|
||||
|
||||
try:
|
||||
self.serialhandler.set_channel(13)
|
||||
self.kismet.send_message("Found band \'2.4GHz\' for freaklabs source on \'{}\'".format(device))
|
||||
return "2400"
|
||||
except FreaklabException as e:
|
||||
return "unknown"
|
||||
|
||||
def __start_monitor(self):
|
||||
def mon_func():
|
||||
while self.kismet.is_running():
|
||||
try:
|
||||
raw = self.serialhandler.read_frame()
|
||||
except FreaklabException as e:
|
||||
self.kismet.send_datasource_error_report(message = "Error reading from zigbee device: {}".format(e))
|
||||
break
|
||||
|
||||
if len(raw) == 0:
|
||||
continue
|
||||
|
||||
packet = kismetexternal.datasource_pb2.SubPacket()
|
||||
dt = datetime.now()
|
||||
packet.time_sec = int(time.mktime(dt.timetuple()))
|
||||
packet.time_usec = int(dt.microsecond)
|
||||
|
||||
packet.dlt = LINKTYPE_IEEE802_15_4_NOFCS
|
||||
|
||||
packet.size = len(raw)
|
||||
packet.data = raw
|
||||
|
||||
self.kismet.send_datasource_data_report(full_packet = packet)
|
||||
|
||||
self.monitor_thread = None
|
||||
|
||||
if self.monitor_thread:
|
||||
return
|
||||
|
||||
self.monitor_thread = threading.Thread(target = mon_func)
|
||||
self.monitor_thread.daemon = True
|
||||
self.monitor_thread.start()
|
||||
|
||||
# We can't really list interfaces other than to guess about serial ports which
|
||||
# seems like a bad idea; maybe we do that, eventually
|
||||
def datasource_listinterfaces(self, seqno):
|
||||
interfaces = []
|
||||
self.kismet.send_datasource_interfaces_report(seqno, interfaces)
|
||||
|
||||
def __get_uuid(self, opts):
|
||||
if ('uuid' in opts):
|
||||
return opts['uuid']
|
||||
|
||||
uhash = kismetexternal.Datasource.adler32("{}{}{}".format(opts['device'], opts['baudrate'], opts['name']))
|
||||
uhex = "0000{:02X}".format(uhash)
|
||||
|
||||
return kismetexternal.Datasource.make_uuid("kismet_cap_freaklabs_zigbee", uhex)
|
||||
|
||||
# Implement the probesource callback for the datasource api
|
||||
def datasource_probesource(self, source, options):
|
||||
ret = {}
|
||||
|
||||
if not source == "freaklabs":
|
||||
return None
|
||||
|
||||
opts = options
|
||||
for x in self.defaults:
|
||||
opts.setdefault(x, self.defaults[x])
|
||||
|
||||
ret['uuid'] = self.__get_uuid(opts)
|
||||
|
||||
try:
|
||||
SerialInputHandler(opts['device'], int(opts['baudrate']))
|
||||
except FreaklabException as e:
|
||||
ret['success'] = False
|
||||
ret['message'] = "{}".format(e)
|
||||
return ret
|
||||
|
||||
ret['capture_interface'] = opts['device']
|
||||
if not opts['band'] == 'auto':
|
||||
ret['hardware'] = "freaklabs-{}".format(opts['band'])
|
||||
|
||||
ret['success'] = True
|
||||
return ret
|
||||
|
||||
def datasource_opensource(self, source, options):
|
||||
ret = {}
|
||||
|
||||
if not source == "freaklabs":
|
||||
return None
|
||||
|
||||
opts = options
|
||||
for x in self.defaults:
|
||||
opts.setdefault(x, self.defaults[x])
|
||||
|
||||
ret['uuid'] = self.__get_uuid(opts)
|
||||
|
||||
try:
|
||||
self.serialhandler = SerialInputHandler(opts['device'], int(opts['baudrate']))
|
||||
self.serialhandler.get_channel()
|
||||
except FreaklabException as e:
|
||||
ret['success'] = False
|
||||
ret['message'] = "{}".format(e)
|
||||
return ret
|
||||
|
||||
# Launch the monitor thread
|
||||
self.__start_monitor()
|
||||
|
||||
while True:
|
||||
try:
|
||||
self.serialhandler.set_channel(2)
|
||||
break
|
||||
except:
|
||||
time.sleep(0.1)
|
||||
|
||||
try:
|
||||
self.serialhandler.set_channel(13)
|
||||
break
|
||||
except:
|
||||
time.sleep(0.4)
|
||||
|
||||
|
||||
if opts['band'] == "auto":
|
||||
opts['band'] = self.__detect_band(opts['device'])
|
||||
|
||||
if opts['band'] == "unknown":
|
||||
ret['success'] = False
|
||||
ret['message'] = "Failed to auto-detect band"
|
||||
return ret
|
||||
|
||||
if not opts['band'] in self.band_map:
|
||||
ret['success'] = False
|
||||
ret['message'] = "Unknown band {}".format(opts['band'])
|
||||
return ret
|
||||
|
||||
band = self.band_map[opts['band']]
|
||||
|
||||
ret['phy'] = LINKTYPE_IEEE802_15_4_NOFCS
|
||||
|
||||
ret['channel'] = band[0]
|
||||
ret['channels'] = band
|
||||
|
||||
ret['capture_interface'] = opts['device']
|
||||
ret['hardware'] = "freaklabs-{}".format(opts['band'])
|
||||
|
||||
ret['success'] = True
|
||||
|
||||
return ret
|
||||
|
||||
def datasource_configure(self, seqno, config):
|
||||
ret = {}
|
||||
|
||||
if config.HasField('channel'):
|
||||
self.chan_config_lock.acquire()
|
||||
self.chan_config['hopping'] = False
|
||||
self.chan_config['channel'] = config.channel.channel
|
||||
ret['channel'] = config.channel.channel
|
||||
self.chan_config_lock.release()
|
||||
elif config.HasField('hopping'):
|
||||
self.chan_config_lock.acquire()
|
||||
if config.hopping.HasField('rate'):
|
||||
self.chan_config['hop_rate'] = config.hopping.rate
|
||||
|
||||
if len(config.hopping.channels):
|
||||
self.chan_config['hop_channels'] = []
|
||||
for c in config.hopping.channels:
|
||||
self.chan_config['hop_channels'].append(c)
|
||||
|
||||
self.chan_config['hopping'] = True
|
||||
|
||||
self.chan_config_lock.release()
|
||||
|
||||
# Echo its config back at it
|
||||
ret['full_hopping'] = config.hopping
|
||||
|
||||
ret['success'] = True
|
||||
|
||||
if self.chan_config['hopping'] and not self.hop_thread:
|
||||
self.__start_hopping()
|
||||
|
||||
return ret
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,18 +0,0 @@
|
|||
include ../Makefile.inc
|
||||
|
||||
MONITOR_BIN = kismet_cap_freaklabs_zigbee
|
||||
|
||||
all:
|
||||
( cd KismetCaptureFreaklabsZigbee/kismetexternal; \
|
||||
$(PROTOCBIN) -I ../../../protobuf_definitions --python_out=. ../../../protobuf_definitions/*.proto; \
|
||||
sed -i -E 's/^import.*_pb2/from . \0/' *_pb2.py ; \
|
||||
)
|
||||
$(PYTHON2) ./setup.py bdist
|
||||
|
||||
install:
|
||||
$(PYTHON2) ./setup.py install
|
||||
# $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) $(MONITOR_BIN) $(BIN)/$(MONITOR_BIN)
|
||||
|
||||
clean:
|
||||
@-$(PYTHON2) ./setup.py clean
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
Kismet Freaklabs Zigbee Support
|
||||
|
||||
- UNDER DEVELOPMENT -
|
||||
|
||||
The zigbee support in Kismet is under heavy development, and not all features
|
||||
are complete at this time; specifically, there is currently no PHY decoder
|
||||
for 802.15.4 in Kismet; this means Kismet *will log 802.15.4 packets to
|
||||
the Kismet databaselog, and to pcap files* but will *not detect or display
|
||||
zigbee devices at this time*.
|
||||
|
||||
If you'd like to contribute to the Zigbee effort, swing by the Kismet Discord
|
||||
or IRC channels (via https://www.kismetwireless.net) or hit me up on Twitter
|
||||
at @KismetWireless; pcaps of wild zigbee data will be greatly appreciated.
|
||||
|
||||
- FREAKLABS ZIGBEE -
|
||||
|
||||
This datasource supports the Freaklabs Zigbee line of products, available
|
||||
at:
|
||||
|
||||
https://freaklabsstore.com/index.php?main_page=product_info&cPath=22&products_id=215
|
||||
and
|
||||
https://freaklabsstore.com/index.php?main_page=product_info&cPath=22&products_id=216
|
||||
|
||||
It likely will support any other hardware which can run the Chibi-Arduino
|
||||
environment or the SenSniff firmware.
|
||||
|
||||
The Kismet sensniff driver is based on the Sensniff python implementation available
|
||||
at:
|
||||
https://github.com/freaklabs/sensniff-freaklabs.git
|
||||
|
||||
Support for other devices will come in other drivers.
|
||||
|
||||
- CONFIGURING YOUR FREAKLABS DEVICE -
|
||||
|
||||
You will need to configure your Freaklabs device to run the sensniff firmware;
|
||||
At its most basic, this means:
|
||||
|
||||
- Installing the latest Arduino environment (likely newer than your distribution
|
||||
packages)
|
||||
- Installing the Freaklabs board definitions in the Arduino IDE
|
||||
- Installing the Freaklabs chibi-arduino library in the Arduino IDE
|
||||
- Building the chibi_ex10_sensniff example
|
||||
- Installing the sensniff firmware on your Freaklabs device.
|
||||
|
||||
The complete directions for configuring Arduino for Freaklabs are available at
|
||||
the store lists for each device in the manual PDF.
|
||||
|
||||
- INSTALLING THE FREAKLABS DATASOURCE -
|
||||
|
||||
The freaklabs-zigbee Kismet datasource uses the Python interface to Kismet; you will
|
||||
need to install the Python modules. This will be done for you in most situations;
|
||||
check the output of `./configure` for more information.
|
||||
|
||||
- CONFIGURING KISMET -
|
||||
|
||||
Freaklabs devices are handled as a 'freaklabs' source. Because they use a standard
|
||||
serial port interface, Kismet cannot automatically detect them; you will need to
|
||||
provide a source definition for each device, for example:
|
||||
|
||||
source=freaklabs:device=/dev/ttyUSB0,name=freak1,band=900
|
||||
|
||||
will tell Kismet to initialize a Freaklabs device on /dev/ttyUSB0, and that it is
|
||||
a 900mhz Freaklabs device.
|
||||
|
||||
Additionally, the Freaklabs sources take the following options:
|
||||
|
||||
device=/path/to/device
|
||||
|
||||
Path to USB Serial device. The user Kismet is running as must have
|
||||
read/write access to this device.
|
||||
|
||||
band=800|900|2400
|
||||
|
||||
The radio band this device is capable of tuning to. Different hardware
|
||||
is required for the different bands.
|
||||
|
||||
- ZIGBEE BANDS -
|
||||
|
||||
802.15.4 / Zigbee operates in up to 3 bands. You will need a device for each band.
|
||||
|
||||
800 - Channel 0, European band, single channel
|
||||
900 - Channels 1-11, US/Intl ISM band
|
||||
2400 - Channels 12-26, US/Intl ISM band
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
"""
|
||||
Freaklabs Zigbee Kismet Datasource
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
||||
try:
|
||||
import KismetCaptureFreaklabsZigbee
|
||||
except ImportError as e:
|
||||
print("Could not import the KismetCaptureFreaklabsZigbee Python code; you are likely missing")
|
||||
print("a Python dependency or the KismetCaptureFreaklabsZigbee python module is not installed:")
|
||||
print(e)
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.tracebacklimit = 0
|
||||
|
||||
zig = KismetCaptureFreaklabsZigbee.KismetFreaklabsZigbee()
|
||||
|
||||
# Go into sleep mode
|
||||
while zig.is_running():
|
||||
time.sleep(1)
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(name='KismetCaptureFreaklabsZigbee',
|
||||
version='2018.0.0',
|
||||
description='Kismet Freaklabs Zigbee datasource',
|
||||
author='Mike Kershaw / Dragorn',
|
||||
author_email='dragorn@kismetwireless.net',
|
||||
url='https://www.kismetwireless.net/',
|
||||
install_requires=['protobuf', 'pyserial'],
|
||||
packages=find_packages(),
|
||||
scripts=['kismet_cap_freaklabs_zigbee'],
|
||||
)
|
||||
|
||||
|
|
@ -1,427 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet and of HackRF
|
||||
|
||||
HackRF sweep components based on hackrf_sweep.c from the HackRF
|
||||
project,
|
||||
|
||||
Copyright 2016 Dominic Spill <dominicgs@gmail.com>
|
||||
Copyright 2016 Mike Walters <mike@flomp.net>
|
||||
Copyright 2017 Michael Ossmann <mike@ossmann.com>
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* capture_hackrf_sweep
|
||||
*
|
||||
* Capture binary which interfaces to the HackRF radio to gather spectrum
|
||||
* measurement which is then reported to Kismet via the SPECTRUM kv pairs.
|
||||
*
|
||||
* This binary only needs to run as root if the hackrf device is not writeable
|
||||
* by the user (as configured in udev); user access is assumed.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <getopt.h>
|
||||
#include <pthread.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sched.h>
|
||||
|
||||
/* According to POSIX.1-2001, POSIX.1-2008 */
|
||||
#include <sys/select.h>
|
||||
|
||||
/* According to earlier standards */
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <ifaddrs.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "simple_datasource_proto.h"
|
||||
#include "capture_framework.h"
|
||||
|
||||
|
||||
#ifndef BUILD_CAPTURE_HACKRF_SWEEP
|
||||
|
||||
/* If the required libraries (hackrf and fftw3) are not available, build the
|
||||
* capture binary, but only return errors.
|
||||
*/
|
||||
|
||||
|
||||
int open_callback(kis_capture_handler_t *, uint32_t, char *,
|
||||
char *msg, uint32_t *, char **, simple_cap_proto_frame_t *,
|
||||
cf_params_interface_t **, cf_params_spectrum_t **) {
|
||||
|
||||
snprintf(msg, STATUS_MAX, "Kismet was not compiled with the hackrf libraries, "
|
||||
"cannot use hackrf_sweep; check the results of ./configure or consult "
|
||||
"your distribution documentation");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int probe_callback(kis_capture_handler_t *, uint32_t, char *,
|
||||
char *msg, char **, simple_cap_proto_frame_t *,
|
||||
cf_params_interface_t **, cf_params_spectrum_t **) {
|
||||
|
||||
snprintf(msg, STATUS_MAX, "Kismet was not compiled with the hackrf libraries, "
|
||||
"cannot use hackrf_sweep; check the results of ./configure or consult "
|
||||
"your distribution documentation");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int list_callback(kis_capture_handler_t *, uint32_t,
|
||||
char *, char ***interfaces, char ***flags) {
|
||||
|
||||
*interfaces = NULL;
|
||||
*flags = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void capture_thread(kis_capture_handler_t *) {
|
||||
return;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <libhackrf/hackrf.h>
|
||||
#include <fftw3.h>
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
|
||||
/* Copied directly from hackrf_sweep.c */
|
||||
#define FD_BUFFER_SIZE (8*1024)
|
||||
|
||||
#define FREQ_ONE_MHZ (1000000ull)
|
||||
|
||||
#define FREQ_MIN_MHZ (0) /* 0 MHz */
|
||||
#define FREQ_MAX_MHZ (7250) /* 7250 MHz */
|
||||
|
||||
#define DEFAULT_SAMPLE_RATE_HZ (20000000) /* 20MHz default sample rate */
|
||||
#define DEFAULT_BASEBAND_FILTER_BANDWIDTH (15000000) /* 5MHz default */
|
||||
|
||||
#define TUNE_STEP (DEFAULT_SAMPLE_RATE_HZ / FREQ_ONE_MHZ)
|
||||
#define OFFSET 7500000
|
||||
|
||||
#define BLOCKS_PER_TRANSFER 16
|
||||
#define THROWAWAY_BLOCKS 2
|
||||
|
||||
#if defined _WIN32
|
||||
#define sleep(a) Sleep( (a*1000) )
|
||||
#endif
|
||||
|
||||
uint32_t num_samples = SAMPLES_PER_BLOCK;
|
||||
int num_ranges = 0;
|
||||
uint16_t frequencies[MAX_SWEEP_RANGES*2];
|
||||
int step_count;
|
||||
|
||||
static float TimevalDiff(const struct timeval *a, const struct timeval *b) {
|
||||
return (a->tv_sec - b->tv_sec) + 1e-6f * (a->tv_usec - b->tv_usec);
|
||||
}
|
||||
|
||||
int parse_u32(char* s, uint32_t* const value) {
|
||||
uint_fast8_t base = 10;
|
||||
char* s_end;
|
||||
uint64_t ulong_value;
|
||||
|
||||
if( strlen(s) > 2 ) {
|
||||
if( s[0] == '0' ) {
|
||||
if( (s[1] == 'x') || (s[1] == 'X') ) {
|
||||
base = 16;
|
||||
s += 2;
|
||||
} else if( (s[1] == 'b') || (s[1] == 'B') ) {
|
||||
base = 2;
|
||||
s += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s_end = s;
|
||||
ulong_value = strtoul(s, &s_end, base);
|
||||
if( (s != s_end) && (*s_end == 0) ) {
|
||||
*value = (uint32_t)ulong_value;
|
||||
return HACKRF_SUCCESS;
|
||||
} else {
|
||||
return HACKRF_ERROR_INVALID_PARAM;
|
||||
}
|
||||
}
|
||||
|
||||
int parse_u32_range(char* s, uint32_t* const value_min, uint32_t* const value_max) {
|
||||
int result;
|
||||
|
||||
char *sep = strchr(s, ':');
|
||||
if (!sep)
|
||||
return HACKRF_ERROR_INVALID_PARAM;
|
||||
|
||||
*sep = 0;
|
||||
|
||||
result = parse_u32(s, value_min);
|
||||
if (result != HACKRF_SUCCESS)
|
||||
return result;
|
||||
result = parse_u32(sep + 1, value_max);
|
||||
if (result != HACKRF_SUCCESS)
|
||||
return result;
|
||||
|
||||
return HACKRF_SUCCESS;
|
||||
}
|
||||
|
||||
volatile bool do_exit = false;
|
||||
|
||||
FILE* fd = NULL;
|
||||
volatile uint32_t byte_count = 0;
|
||||
volatile uint64_t sweep_count = 0;
|
||||
|
||||
struct timeval time_start;
|
||||
struct timeval t_start;
|
||||
struct timeval time_stamp;
|
||||
|
||||
bool amp = false;
|
||||
uint32_t amp_enable;
|
||||
|
||||
bool antenna = false;
|
||||
uint32_t antenna_enable;
|
||||
|
||||
bool binary_output = false;
|
||||
bool ifft_output = false;
|
||||
bool one_shot = false;
|
||||
volatile bool sweep_started = false;
|
||||
|
||||
int fftSize = 20;
|
||||
double fft_bin_width;
|
||||
fftwf_complex *fftwIn = NULL;
|
||||
fftwf_complex *fftwOut = NULL;
|
||||
fftwf_plan fftwPlan = NULL;
|
||||
fftwf_complex *ifftwIn = NULL;
|
||||
fftwf_complex *ifftwOut = NULL;
|
||||
fftwf_plan ifftwPlan = NULL;
|
||||
uint32_t ifft_idx = 0;
|
||||
float* pwr;
|
||||
float* window;
|
||||
|
||||
float logPower(fftwf_complex in, float scale)
|
||||
{
|
||||
float re = in[0] * scale;
|
||||
float im = in[1] * scale;
|
||||
float magsq = re * re + im * im;
|
||||
return log2f(magsq) * 10.0f / log2(10.0f);
|
||||
}
|
||||
|
||||
|
||||
int probe_callback(kis_capture_handler_t *caph, uint32_t seqno, char *definition,
|
||||
char *msg, char **uuid, simple_cap_proto_frame_t *frame,
|
||||
cf_params_interface_t **ret_interface,
|
||||
cf_params_spectrum_t **ret_spectrum) {
|
||||
char *placeholder = NULL;
|
||||
int placeholder_len;
|
||||
char *interface = NULL;
|
||||
char *serial = NULL;
|
||||
char errstr[STATUS_MAX];
|
||||
hackrf_device_list_t *list;
|
||||
int x;
|
||||
|
||||
*ret_spectrum = cf_params_spectrum_new();
|
||||
*ret_interface = NULL;
|
||||
|
||||
if ((placeholder_len = cf_parse_interface(&placeholder, definition)) <= 0) {
|
||||
snprintf(msg, STATUS_MAX, "Unable to find interface in definition");
|
||||
return 0;
|
||||
}
|
||||
|
||||
interface = strndup(placeholder, placeholder_len);
|
||||
|
||||
// All hackrfsweeps use 'hackrf' as the interface
|
||||
if (strcmp(interface, "hackrf") != 0) {
|
||||
snprintf(msg, STATUS_MAX, "Doesn't look like a hackrf");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (hackrf_init() != HACKRF_SUCCESS) {
|
||||
snprintf(msg, STATUS_MAX, "hackrf_sweep could not initialize libhackrf");
|
||||
return 0;
|
||||
}
|
||||
|
||||
list = hackrf_device_list();
|
||||
|
||||
if (list == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (list->devicecount == 0)
|
||||
return 0;
|
||||
|
||||
|
||||
// Figure out if we have a serial #
|
||||
if ((placeholder_len = cf_find_flag(&placeholder, "serial", definition)) > 0) {
|
||||
serial = strndup(placeholder, placeholder_len);
|
||||
}
|
||||
|
||||
if (serial == NULL && list->devicecount != 1) {
|
||||
snprintf(msg, STATUS_MAX, "multiple hackrf devices found, specify serial number");
|
||||
hackrf_device_list_free(list);
|
||||
hackrf_exit();
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (x = 0; x < list->devicecount; x++) {
|
||||
if (strcmp(serial, list->serial_numbers[x]) == 0) {
|
||||
unsigned long s;
|
||||
if (sscanf(serial, "%lx", &s) == 1) {
|
||||
/* Make a spoofed, but consistent, UUID based on the adler32 of the
|
||||
* capture name and the serial of the device */
|
||||
snprintf(errstr, STATUS_MAX, "%08X-0000-0000-%04lX-%12lX",
|
||||
adler32_csum((unsigned char *) "kismet_cap_hackrf_sweep",
|
||||
strlen("kismet_cap_hackrf_sweep")) & 0xFFFFFFFF,
|
||||
(s >> 48) & 0xFFFF, s & 0xFFFFFFFFFFFF);
|
||||
*uuid = strdup(errstr);
|
||||
|
||||
hackrf_device_list_free(list);
|
||||
hackrf_exit();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
hackrf_device_list_free(list);
|
||||
hackrf_exit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int open_callback(kis_capture_handler_t *caph, uint32_t seqno, char *definition,
|
||||
char *msg, uint32_t *dlt, char **uuid, simple_cap_proto_frame_t *frame,
|
||||
cf_params_interface_t **ret_interface,
|
||||
cf_params_spectrum_t **ret_spectrum) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int list_callback(kis_capture_handler_t *caph, uint32_t seqno,
|
||||
char *msg, char ***interfaces, char ***flags) {
|
||||
|
||||
char errstr[STATUS_MAX];
|
||||
hackrf_device_list_t *list;
|
||||
|
||||
*interfaces = NULL;
|
||||
*flags = NULL;
|
||||
|
||||
int x = 0;
|
||||
|
||||
if (hackrf_init() != HACKRF_SUCCESS) {
|
||||
snprintf(msg, STATUS_MAX, "hackrf_sweep could not initialize libhackrf");
|
||||
return 0;
|
||||
}
|
||||
|
||||
list = hackrf_device_list();
|
||||
|
||||
if (list == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (list->devicecount == 0)
|
||||
return 0;
|
||||
|
||||
*interfaces = (char **) malloc(sizeof(char *) * list->devicecount);
|
||||
*flags = (char **) malloc(sizeof(char *) * list->devicecount);
|
||||
|
||||
for (x = 0; x < list->devicecount; x++) {
|
||||
*interfaces[x] = strdup("hackrf");
|
||||
|
||||
snprintf(errstr, STATUS_MAX, "serial=%s", list->serial_numbers[x]);
|
||||
*flags[x] = strdup(errstr);
|
||||
}
|
||||
|
||||
x = list->devicecount;
|
||||
|
||||
hackrf_device_list_free(list);
|
||||
|
||||
hackrf_exit();
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
void capture_thread(kis_capture_handler_t *caph) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
#if 0
|
||||
local_wifi_t local_wifi = {
|
||||
.pd = NULL,
|
||||
.interface = NULL,
|
||||
.cap_interface = NULL,
|
||||
.datalink_type = -1,
|
||||
.override_dlt = -1,
|
||||
.use_mac80211_vif = 1,
|
||||
.use_mac80211_channels = 1,
|
||||
.mac80211_cache = NULL,
|
||||
.mac80211_handle = NULL,
|
||||
.mac80211_family = NULL,
|
||||
.seq_channel_failure = 0,
|
||||
.reset_nm_management = 0,
|
||||
};
|
||||
#endif
|
||||
|
||||
kis_capture_handler_t *caph = cf_handler_init("hackrfsweep");
|
||||
|
||||
if (caph == NULL) {
|
||||
fprintf(stderr, "FATAL: Could not allocate basic handler data, your system "
|
||||
"is very low on RAM or something is wrong.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Set the local data ptr */
|
||||
cf_handler_set_userdata(caph, &local_wifi);
|
||||
#endif
|
||||
|
||||
/* Set the callback for opening */
|
||||
cf_handler_set_open_cb(caph, open_callback);
|
||||
|
||||
/* Set the callback for probing an interface */
|
||||
cf_handler_set_probe_cb(caph, probe_callback);
|
||||
|
||||
/* Set the list callback */
|
||||
cf_handler_set_listdevices_cb(caph, list_callback);
|
||||
|
||||
/* Set the capture thread */
|
||||
cf_handler_set_capture_cb(caph, capture_thread);
|
||||
|
||||
if (cf_handler_parse_opts(caph, argc, argv) < 1) {
|
||||
cf_print_help(caph, argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cf_handler_loop(caph);
|
||||
|
||||
cf_handler_free(caph);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -1,713 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* capture_kismetdb
|
||||
*
|
||||
* Basic capture binary for reading kismetdb logfiles.
|
||||
*/
|
||||
|
||||
#include <pcap.h>
|
||||
#include <getopt.h>
|
||||
#include <pthread.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
/* According to POSIX.1-2001, POSIX.1-2008 */
|
||||
#include <sys/select.h>
|
||||
|
||||
/* According to earlier standards */
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "capture_framework.h"
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
typedef struct {
|
||||
sqlite3 *db;
|
||||
char *dbname;
|
||||
|
||||
/* Optional filters for sub-sources */
|
||||
char *sub_uuid;
|
||||
int sub_dlt;
|
||||
|
||||
/* Database version */
|
||||
int db_version;
|
||||
|
||||
int realtime;
|
||||
struct timeval last_ts;
|
||||
|
||||
unsigned int pps_throttle;
|
||||
} local_pcap_t;
|
||||
|
||||
/* Version callback */
|
||||
int sqlite_version_cb(void *ver, int argc, char **data, char **colnames) {
|
||||
if (argc != 1) {
|
||||
*((unsigned int *) ver) = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sscanf(data[0], "%u", (unsigned int *) ver) != 1) {
|
||||
*((unsigned int *) ver) = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int probe_callback(kis_capture_handler_t *caph, uint32_t seqno, char *definition,
|
||||
char *msg, char **uuid, KismetExternal__Command *frame,
|
||||
cf_params_interface_t **ret_interface,
|
||||
cf_params_spectrum_t **ret_spectrum) {
|
||||
char *placeholder = NULL;
|
||||
int placeholder_len;
|
||||
|
||||
*uuid = NULL;
|
||||
|
||||
char *dbname = NULL;
|
||||
|
||||
struct stat sbuf;
|
||||
|
||||
char errstr[4096] = "";
|
||||
|
||||
sqlite3 *db;
|
||||
|
||||
int sql_r;
|
||||
|
||||
const char *kismet_version_sql =
|
||||
"SELECT db_version FROM KISMET";
|
||||
unsigned int dbversion = 0;
|
||||
char *sErrMsg = NULL;
|
||||
|
||||
*ret_spectrum = NULL;
|
||||
|
||||
*ret_interface = cf_params_interface_new();
|
||||
*ret_spectrum = NULL;
|
||||
|
||||
/* kismetdb does not support channel ops */
|
||||
(*ret_interface)->chanset = NULL;
|
||||
(*ret_interface)->channels = NULL;
|
||||
(*ret_interface)->channels_len = 0;
|
||||
|
||||
if ((placeholder_len = cf_parse_interface(&placeholder, definition)) <= 0) {
|
||||
snprintf(msg, STATUS_MAX, "Unable to find kismetdb file name in definition");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dbname = strndup(placeholder, placeholder_len);
|
||||
|
||||
if (stat(dbname, &sbuf) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!S_ISREG(sbuf.st_mode)) {
|
||||
snprintf(msg, STATUS_MAX, "Kismetdb '%s' is not a normal file", dbname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sql_r = sqlite3_open(dbname, &db);
|
||||
if (sql_r) {
|
||||
snprintf(msg, STATUS_MAX, "Unable to open kismetdb file: %s", sqlite3_errmsg(db));
|
||||
return 0;
|
||||
}
|
||||
|
||||
sql_r = sqlite3_exec(db, kismet_version_sql, sqlite_version_cb, &dbversion, &sErrMsg);
|
||||
if (sql_r != SQLITE_OK || dbversion == 0) {
|
||||
snprintf(msg, STATUS_MAX, "Unable to find kismetdb version in database %s: %s", dbname, sqlite3_errmsg(db));
|
||||
sqlite3_close(db);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((placeholder_len = cf_find_flag(&placeholder, "uuid", definition)) > 0) {
|
||||
*uuid = strdup(placeholder);
|
||||
} else {
|
||||
/* Kluge a UUID out of the name */
|
||||
snprintf(errstr, 4096, "%08X-0000-0000-0000-0000%08X",
|
||||
adler32_csum((unsigned char *) "kismet_cap_pcapfile",
|
||||
strlen("kismet_cap_kismetdb")) & 0xFFFFFFFF,
|
||||
adler32_csum((unsigned char *) dbname,
|
||||
strlen(dbname)) & 0xFFFFFFFF);
|
||||
*uuid = strdup(errstr);
|
||||
}
|
||||
|
||||
sqlite3_close(db);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int open_callback(kis_capture_handler_t *caph, uint32_t seqno, char *definition,
|
||||
char *msg, uint32_t *dlt, char **uuid, KismetExternal__Command *frame,
|
||||
cf_params_interface_t **ret_interface,
|
||||
cf_params_spectrum_t **ret_spectrum) {
|
||||
char *placeholder = NULL;
|
||||
int placeholder_len;
|
||||
|
||||
char *dbname = NULL;
|
||||
|
||||
struct stat sbuf;
|
||||
|
||||
local_pcap_t *local_pcap = (local_pcap_t *) caph->userdata;
|
||||
|
||||
char errstr[4096] = "";
|
||||
|
||||
/* pcapfile does not support channel ops */
|
||||
*ret_interface = cf_params_interface_new();
|
||||
*ret_spectrum = NULL;
|
||||
|
||||
*uuid = NULL;
|
||||
*dlt = 0;
|
||||
|
||||
int sql_r;
|
||||
|
||||
const char *kismet_version_sql =
|
||||
"SELECT db_version FROM KISMET";
|
||||
char *sErrMsg = NULL;
|
||||
|
||||
/* Clean up any old state */
|
||||
if (local_pcap->dbname != NULL) {
|
||||
free(local_pcap->dbname);
|
||||
local_pcap->dbname = NULL;
|
||||
}
|
||||
|
||||
if (local_pcap->db != NULL) {
|
||||
sqlite3_close(local_pcap->db);
|
||||
local_pcap->db = NULL;
|
||||
}
|
||||
|
||||
if ((placeholder_len = cf_parse_interface(&placeholder, definition)) <= 0) {
|
||||
/* What was not an error during probe definitely is an error during open */
|
||||
snprintf(msg, STATUS_MAX, "Unable to find PCAP file name in definition");
|
||||
return -1;
|
||||
}
|
||||
|
||||
dbname = strndup(placeholder, placeholder_len);
|
||||
|
||||
local_pcap->dbname = dbname;
|
||||
|
||||
if (stat(dbname, &sbuf) < 0) {
|
||||
snprintf(msg, STATUS_MAX, "Could not stat() file '%s', something is very odd", dbname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!S_ISREG(sbuf.st_mode)) {
|
||||
snprintf(msg, STATUS_MAX, "Kismetdb '%s' is not a normal file", dbname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sql_r = sqlite3_open(dbname, &local_pcap->db);
|
||||
if (sql_r) {
|
||||
snprintf(msg, STATUS_MAX, "Unable to open kismetdb file: %s", sqlite3_errmsg(local_pcap->db));
|
||||
return -1;
|
||||
}
|
||||
|
||||
sql_r = sqlite3_exec(local_pcap->db, kismet_version_sql, sqlite_version_cb, &(local_pcap->db_version), &sErrMsg);
|
||||
if (sql_r != SQLITE_OK || local_pcap->db_version == 0) {
|
||||
snprintf(msg, STATUS_MAX, "Unable to find kismetdb version in database %s: %s", dbname, sqlite3_errmsg(local_pcap->db));
|
||||
sqlite3_close(local_pcap->db);
|
||||
local_pcap->db = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((placeholder_len = cf_find_flag(&placeholder, "uuid", definition)) > 0) {
|
||||
*uuid = strdup(placeholder);
|
||||
} else {
|
||||
/* Kluge a UUID out of the name */
|
||||
snprintf(errstr, 4096, "%08X-0000-0000-0000-0000%08X",
|
||||
adler32_csum((unsigned char *) "kismet_cap_pcapfile",
|
||||
strlen("kismet_cap_kismetdb")) & 0xFFFFFFFF,
|
||||
adler32_csum((unsigned char *) dbname,
|
||||
strlen(dbname)) & 0xFFFFFFFF);
|
||||
*uuid = strdup(errstr);
|
||||
}
|
||||
|
||||
/* Succesful open with no channel, hop, or chanset data */
|
||||
snprintf(msg, STATUS_MAX, "Opened kismetdb '%s' for playback", dbname);
|
||||
|
||||
if ((placeholder_len = cf_find_flag(&placeholder, "realtime", definition)) > 0) {
|
||||
if (strncasecmp(placeholder, "true", placeholder_len) == 0) {
|
||||
snprintf(errstr, 4096,
|
||||
"kismetdb '%s' will replay in realtime", dbname);
|
||||
cf_send_message(caph, errstr, MSGFLAG_INFO);
|
||||
local_pcap->realtime = 1;
|
||||
}
|
||||
} else if ((placeholder_len = cf_find_flag(&placeholder, "pps", definition)) > 0) {
|
||||
unsigned int pps;
|
||||
if (sscanf(placeholder, "%u", &pps) == 1) {
|
||||
snprintf(errstr, 4096,
|
||||
"kismetdb '%s' will throttle to %u packets per second", dbname, pps);
|
||||
cf_send_message(caph, errstr,MSGFLAG_INFO);
|
||||
local_pcap->pps_throttle = pps;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void kismetdb_dispatch_packet_cb(u_char *user, long ts_sec, long ts_usec,
|
||||
unsigned int dlt, uint32_t len, const u_char *data,
|
||||
double lat, double lon, double alt, double speed, double heading) {
|
||||
|
||||
kis_capture_handler_t *caph = (kis_capture_handler_t *) user;
|
||||
local_pcap_t *local_pcap = (local_pcap_t *) caph->userdata;
|
||||
int ret;
|
||||
unsigned long delay_usec = 0;
|
||||
|
||||
KismetDatasource__SubGps kegps;
|
||||
|
||||
kismet_datasource__sub_gps__init(&kegps);
|
||||
|
||||
/* If we're doing 'realtime' playback, delay accordingly based on the
|
||||
* previous packet.
|
||||
*
|
||||
* Because we're in our own thread, we can block as long as we want - this
|
||||
* simulates blocking IO for capturing from hardware, too.
|
||||
*/
|
||||
if (local_pcap->realtime) {
|
||||
if (local_pcap->last_ts.tv_sec == 0 && local_pcap->last_ts.tv_usec == 0) {
|
||||
delay_usec = 0;
|
||||
} else {
|
||||
/* Catch packets with inconsistent times */
|
||||
if (ts_sec < local_pcap->last_ts.tv_sec) {
|
||||
delay_usec = 0;
|
||||
} else {
|
||||
delay_usec = (ts_sec - local_pcap->last_ts.tv_sec) * 1000000L;
|
||||
}
|
||||
|
||||
if (ts_usec < local_pcap->last_ts.tv_usec) {
|
||||
delay_usec += (1000000L - local_pcap->last_ts.tv_usec) + ts_usec;
|
||||
} else {
|
||||
delay_usec += ts_usec - local_pcap->last_ts.tv_usec;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
local_pcap->last_ts.tv_sec = ts_sec;
|
||||
local_pcap->last_ts.tv_usec = ts_usec;
|
||||
|
||||
if (delay_usec != 0) {
|
||||
usleep(delay_usec);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're doing 'packet per second' throttling, delay accordingly */
|
||||
if (local_pcap->pps_throttle > 0) {
|
||||
delay_usec = 1000000L / local_pcap->pps_throttle;
|
||||
|
||||
if (delay_usec != 0)
|
||||
usleep(delay_usec);
|
||||
}
|
||||
|
||||
/* Fill in the GPS */
|
||||
kegps.lat = lat;
|
||||
kegps.lon = lon;
|
||||
kegps.alt = alt;
|
||||
kegps.heading = heading;
|
||||
|
||||
if (alt != 0)
|
||||
kegps.fix = 3;
|
||||
else
|
||||
kegps.fix = 2;
|
||||
|
||||
kegps.time_sec = ts_sec;
|
||||
kegps.time_usec = ts_usec;
|
||||
|
||||
kegps.type = strdup("kismetdb");
|
||||
kegps.name = strdup("kismetdb");
|
||||
|
||||
struct timeval ts;
|
||||
ts.tv_sec = ts_sec;
|
||||
ts.tv_usec = ts_usec;
|
||||
|
||||
/* Try repeatedly to send the packet; go into a thread wait state if
|
||||
* the write buffer is full & we'll be woken up as soon as it flushes
|
||||
* data out in the main select() loop */
|
||||
while (1) {
|
||||
if ((ret = cf_send_data(caph,
|
||||
NULL, NULL, &kegps,
|
||||
ts,
|
||||
dlt,
|
||||
len, (uint8_t *) data)) < 0) {
|
||||
cf_send_error(caph, 0, "unable to send DATA frame");
|
||||
cf_handler_spindown(caph);
|
||||
} else if (ret == 0) {
|
||||
/* Go into a wait for the write buffer to get flushed */
|
||||
// fprintf(stderr, "debug - pcapfile - dispatch_cb - no room in write buffer - waiting for it to have more space\n");
|
||||
cf_handler_wait_ringbuffer(caph);
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (kegps.name != NULL)
|
||||
free(kegps.name);
|
||||
if (kegps.type != NULL)
|
||||
free(kegps.type);
|
||||
}
|
||||
|
||||
void kismetdb_dispatch_data_cb(u_char *user, long ts_sec, long ts_usec,
|
||||
char *type, char *json,
|
||||
double lat, double lon, double alt, double speed, double heading) {
|
||||
|
||||
kis_capture_handler_t *caph = (kis_capture_handler_t *) user;
|
||||
local_pcap_t *local_pcap = (local_pcap_t *) caph->userdata;
|
||||
int ret;
|
||||
unsigned long delay_usec = 0;
|
||||
|
||||
KismetDatasource__SubGps kegps;
|
||||
kismet_datasource__sub_gps__init(&kegps);
|
||||
|
||||
/* If we're doing 'realtime' playback, delay accordingly based on the
|
||||
* previous packet.
|
||||
*
|
||||
* Because we're in our own thread, we can block as long as we want - this
|
||||
* simulates blocking IO for capturing from hardware, too.
|
||||
*/
|
||||
if (local_pcap->realtime) {
|
||||
if (local_pcap->last_ts.tv_sec == 0 && local_pcap->last_ts.tv_usec == 0) {
|
||||
delay_usec = 0;
|
||||
} else {
|
||||
/* Catch packets with inconsistent times */
|
||||
if (ts_sec < local_pcap->last_ts.tv_sec) {
|
||||
delay_usec = 0;
|
||||
} else {
|
||||
delay_usec = (ts_sec - local_pcap->last_ts.tv_sec) * 1000000L;
|
||||
}
|
||||
|
||||
if (ts_usec < local_pcap->last_ts.tv_usec) {
|
||||
delay_usec += (1000000L - local_pcap->last_ts.tv_usec) + ts_usec;
|
||||
} else {
|
||||
delay_usec += ts_usec - local_pcap->last_ts.tv_usec;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
local_pcap->last_ts.tv_sec = ts_sec;
|
||||
local_pcap->last_ts.tv_usec = ts_usec;
|
||||
|
||||
if (delay_usec != 0) {
|
||||
usleep(delay_usec);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're doing 'packet per second' throttling, delay accordingly */
|
||||
if (local_pcap->pps_throttle > 0) {
|
||||
delay_usec = 1000000L / local_pcap->pps_throttle;
|
||||
|
||||
if (delay_usec != 0)
|
||||
usleep(delay_usec);
|
||||
}
|
||||
|
||||
/* Fill in the GPS */
|
||||
kegps.lat = lat;
|
||||
kegps.lon = lon;
|
||||
kegps.alt = alt;
|
||||
kegps.heading = heading;
|
||||
|
||||
if (alt != 0)
|
||||
kegps.fix = 3;
|
||||
else
|
||||
kegps.fix = 2;
|
||||
|
||||
kegps.time_sec = ts_sec;
|
||||
kegps.time_usec = ts_usec;
|
||||
|
||||
kegps.type = strdup("kismetdb");
|
||||
kegps.name = strdup("kismetdb");
|
||||
|
||||
struct timeval ts;
|
||||
ts.tv_sec = ts_sec;
|
||||
ts.tv_usec = ts_usec;
|
||||
|
||||
/* Try repeatedly to send the packet; go into a thread wait state if
|
||||
* the write buffer is full & we'll be woken up as soon as it flushes
|
||||
* data out in the main select() loop */
|
||||
while (1) {
|
||||
if ((ret = cf_send_json(caph,
|
||||
NULL, NULL, &kegps,
|
||||
ts,
|
||||
type, json)) < 0) {
|
||||
cf_send_error(caph, 0, "unable to send DATA frame");
|
||||
cf_handler_spindown(caph);
|
||||
} else if (ret == 0) {
|
||||
/* Go into a wait for the write buffer to get flushed */
|
||||
// fprintf(stderr, "debug - pcapfile - dispatch_cb - no room in write buffer - waiting for it to have more space\n");
|
||||
cf_handler_wait_ringbuffer(caph);
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (kegps.name != NULL)
|
||||
free(kegps.name);
|
||||
if (kegps.type != NULL)
|
||||
free(kegps.type);
|
||||
}
|
||||
|
||||
void capture_thread(kis_capture_handler_t *caph) {
|
||||
local_pcap_t *local_pcap = (local_pcap_t *) caph->userdata;
|
||||
|
||||
char errstr[4096];
|
||||
|
||||
int sql_r;
|
||||
|
||||
sqlite3_stmt *packet_stmt = NULL;
|
||||
const char *packet_pz = NULL;
|
||||
|
||||
sqlite3_stmt *data_stmt = NULL;
|
||||
const char *data_pz = NULL;
|
||||
|
||||
int packet_r, data_r;
|
||||
|
||||
/* Common between both packets and data */
|
||||
double lat = 0, lon = 0, alt = 0, speed = 0, heading = 0;
|
||||
|
||||
/* Last packet timestamp */
|
||||
long packet_ts_sec, packet_ts_usec;
|
||||
|
||||
/* Packet data */
|
||||
unsigned int packet_len;
|
||||
const void *packet_data;
|
||||
double packet_frequency;
|
||||
int dlt;
|
||||
|
||||
/* Last data timestamp */
|
||||
long data_ts_sec, data_ts_usec;
|
||||
|
||||
/* Data... data... */
|
||||
char *data_type = NULL;
|
||||
char *data_json = NULL;
|
||||
|
||||
/* V4 didn't have speed, heading, etc, and used the normalized encoding */
|
||||
const char *basic_packet_sql_v4 =
|
||||
"SELECT ts_sec, ts_usec, frequency, (lat / 100000.0), (lon / 100000.0), dlt, packet FROM packets ORDER BY ts_sec, ts_usec";
|
||||
|
||||
const char *basic_data_sql_v4 =
|
||||
"SELECT ts_sec, ts_usec, (lat / 100000.0), (lon / 100000.0), type, json FROM data ORDER BY ts_sec, ts_usec";
|
||||
|
||||
|
||||
/* V5 has full GPS, and in natural doubles */
|
||||
const char *basic_packet_sql_v5 =
|
||||
"SELECT ts_sec, ts_usec, frequency, lat, lon, alt, speed, heading, dlt, packet FROM packets ORDER BY ts_sec, ts_usec";
|
||||
|
||||
const char *basic_data_sql_v5 =
|
||||
"SELECT ts_sec, ts_usec, lat, lon, alt, speed, heading, type, json FROM data ORDER BY ts_sec, ts_usec";
|
||||
|
||||
int colno;
|
||||
|
||||
if (local_pcap->db_version <= 4) {
|
||||
sql_r = sqlite3_prepare(local_pcap->db, basic_packet_sql_v4, strlen(basic_packet_sql_v4), &packet_stmt, &packet_pz);
|
||||
} else if (local_pcap->db_version >= 5) {
|
||||
sql_r = sqlite3_prepare(local_pcap->db, basic_packet_sql_v5, strlen(basic_packet_sql_v5), &packet_stmt, &packet_pz);
|
||||
} else {
|
||||
sql_r = SQLITE_ERROR;
|
||||
}
|
||||
|
||||
if (sql_r != SQLITE_OK) {
|
||||
snprintf(errstr, 4096, "KismetDB '%s' could not prepare packet query: %s",
|
||||
local_pcap->dbname, sqlite3_errmsg(local_pcap->db));
|
||||
cf_send_error(caph, 0, errstr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (local_pcap->db_version <= 4) {
|
||||
sql_r = sqlite3_prepare(local_pcap->db, basic_data_sql_v4, strlen(basic_data_sql_v4), &data_stmt, &data_pz);
|
||||
} else if (local_pcap->db_version >= 5) {
|
||||
sql_r = sqlite3_prepare(local_pcap->db, basic_data_sql_v5, strlen(basic_data_sql_v5), &data_stmt, &data_pz);
|
||||
} else {
|
||||
sql_r = SQLITE_ERROR;
|
||||
}
|
||||
|
||||
if (sql_r != SQLITE_OK) {
|
||||
snprintf(errstr, 4096, "KismetDB '%s' could not prepare data query: %s",
|
||||
local_pcap->dbname, sqlite3_errmsg(local_pcap->db));
|
||||
cf_send_error(caph, 0, errstr);
|
||||
return;
|
||||
}
|
||||
|
||||
sql_r = sqlite3_reset(packet_stmt);
|
||||
if (sql_r != SQLITE_OK) {
|
||||
snprintf(errstr, 4096, "KismetDB '%s' could not prepare packet query: %s",
|
||||
local_pcap->dbname, sqlite3_errmsg(local_pcap->db));
|
||||
cf_send_error(caph, 0, errstr);
|
||||
return;
|
||||
}
|
||||
|
||||
sql_r = sqlite3_reset(data_stmt);
|
||||
if (sql_r != SQLITE_OK) {
|
||||
snprintf(errstr, 4096, "KismetDB '%s' could not prepare data query: %s",
|
||||
local_pcap->dbname, sqlite3_errmsg(local_pcap->db));
|
||||
cf_send_error(caph, 0, errstr);
|
||||
return;
|
||||
}
|
||||
|
||||
packet_r = sqlite3_step(packet_stmt);
|
||||
data_r = sqlite3_step(data_stmt);
|
||||
|
||||
while (packet_r == SQLITE_ROW || data_r == SQLITE_ROW) {
|
||||
lat = 0;
|
||||
lon = 0;
|
||||
alt = 0;
|
||||
speed = 0;
|
||||
heading = 0;
|
||||
|
||||
if (packet_r == SQLITE_ROW) {
|
||||
packet_ts_sec = sqlite3_column_int64(packet_stmt, 0);
|
||||
packet_ts_usec = sqlite3_column_int64(packet_stmt, 1);
|
||||
} else {
|
||||
packet_ts_sec = 0;
|
||||
packet_ts_usec = 0;
|
||||
}
|
||||
|
||||
if (data_r == SQLITE_ROW) {
|
||||
data_ts_sec = sqlite3_column_int64(data_stmt, 0);
|
||||
data_ts_usec = sqlite3_column_int64(data_stmt, 1);
|
||||
} else {
|
||||
data_ts_sec = 0;
|
||||
data_ts_usec = 0;
|
||||
}
|
||||
|
||||
/* Merge the timelines of the two tables; if the packet comes first process it,
|
||||
* otherwise process the data, and repeat */
|
||||
if (data_ts_sec == 0 || packet_ts_sec < data_ts_sec ||
|
||||
(packet_ts_sec == data_ts_sec && packet_ts_usec < data_ts_usec)) {
|
||||
colno = 2;
|
||||
|
||||
packet_frequency = sqlite3_column_double(packet_stmt, colno++);
|
||||
|
||||
lat = sqlite3_column_double(packet_stmt, colno++);
|
||||
lon = sqlite3_column_double(packet_stmt, colno++);
|
||||
|
||||
if (local_pcap->db_version >= 5) {
|
||||
alt = sqlite3_column_double(packet_stmt, colno++);
|
||||
speed = sqlite3_column_double(packet_stmt, colno++);
|
||||
heading = sqlite3_column_double(packet_stmt, colno++);
|
||||
}
|
||||
|
||||
dlt = sqlite3_column_int(packet_stmt, colno++);
|
||||
|
||||
packet_len = sqlite3_column_bytes(packet_stmt, colno);
|
||||
packet_data = sqlite3_column_blob(packet_stmt, colno++);
|
||||
|
||||
kismetdb_dispatch_packet_cb((u_char *) caph, packet_ts_sec, packet_ts_usec, dlt,
|
||||
packet_len, (const u_char *) packet_data,
|
||||
lat, lon, alt, speed, heading);
|
||||
|
||||
packet_r = sqlite3_step(packet_stmt);
|
||||
} else {
|
||||
colno = 2;
|
||||
|
||||
lat = sqlite3_column_double(data_stmt, colno++);
|
||||
lon = sqlite3_column_double(data_stmt, colno++);
|
||||
|
||||
if (local_pcap->db_version >= 5) {
|
||||
alt = sqlite3_column_double(data_stmt, colno++);
|
||||
speed = sqlite3_column_double(data_stmt, colno++);
|
||||
heading = sqlite3_column_double(data_stmt, colno++);
|
||||
}
|
||||
|
||||
data_type = strdup((const char *) sqlite3_column_text(data_stmt, colno++));
|
||||
data_json = strdup((const char *) sqlite3_column_text(data_stmt, colno++));
|
||||
|
||||
kismetdb_dispatch_data_cb((u_char *) caph, packet_ts_sec, packet_ts_usec,
|
||||
data_type, data_json,
|
||||
lat, lon, alt, speed, heading);
|
||||
|
||||
free(data_type);
|
||||
free(data_json);
|
||||
|
||||
data_r = sqlite3_step(data_stmt);
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(errstr, 4096, "KismetDB '%s' closed, all packets and data processed.",
|
||||
local_pcap->dbname);
|
||||
cf_send_message(caph, errstr, MSGFLAG_INFO);
|
||||
|
||||
/* Instead of dying, spin forever in a sleep loop */
|
||||
while (1) {
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
/* cf_handler_spindown(caph); */
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
local_pcap_t local_pcap = {
|
||||
.db = NULL,
|
||||
.dbname = NULL,
|
||||
.sub_uuid = NULL,
|
||||
.sub_dlt = 0,
|
||||
.realtime = 0,
|
||||
.last_ts.tv_sec = 0,
|
||||
.last_ts.tv_usec = 0,
|
||||
.pps_throttle = 0,
|
||||
};
|
||||
|
||||
#if 0
|
||||
/* Remap stderr so we can log debugging to a file */
|
||||
FILE *sterr;
|
||||
sterr = fopen("/tmp/capture_pcapfile.stderr", "a");
|
||||
dup2(fileno(sterr), STDERR_FILENO);
|
||||
#endif
|
||||
|
||||
/* fprintf(stderr, "CAPTURE_PCAPFILE launched on pid %d\n", getpid()); */
|
||||
|
||||
kis_capture_handler_t *caph = cf_handler_init("kismetdb");
|
||||
|
||||
if (caph == NULL) {
|
||||
fprintf(stderr, "FATAL: Could not allocate basic handler data, your system "
|
||||
"is very low on RAM or something is wrong.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set the local data ptr */
|
||||
cf_handler_set_userdata(caph, &local_pcap);
|
||||
|
||||
/* Set the callback for opening a pcapfile */
|
||||
cf_handler_set_open_cb(caph, open_callback);
|
||||
|
||||
/* Set the callback for probing an interface */
|
||||
cf_handler_set_probe_cb(caph, probe_callback);
|
||||
|
||||
/* Set the capture thread */
|
||||
cf_handler_set_capture_cb(caph, capture_thread);
|
||||
|
||||
if (cf_handler_parse_opts(caph, argc, argv) < 1) {
|
||||
cf_print_help(caph, argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Support remote capture by launching the remote loop */
|
||||
cf_handler_remote_capture(caph);
|
||||
|
||||
cf_handler_loop(caph);
|
||||
|
||||
cf_handler_free(caph);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
include ../Makefile.inc
|
||||
|
||||
MONITOR_OBJS = \
|
||||
linux_bt_rfkill.c.o \
|
||||
capture_linux_bluetooth.c.o
|
||||
MONITOR_BIN = kismet_cap_linux_bluetooth
|
||||
|
||||
all: $(MONITOR_BIN)
|
||||
|
||||
$(MONITOR_BIN): $(MONITOR_OBJS) $(patsubst %c.o,%c.d,$(MONITOR_OBJS)) ../libkismetdatasource.a
|
||||
$(CCLD) $(LDFLAGS) -o $(MONITOR_BIN) $(MONITOR_OBJS) ../libkismetdatasource.a $(DATASOURCE_LIBS)
|
||||
|
||||
clean:
|
||||
@-rm -f $(MONITOR_BIN)
|
||||
@-rm -f *.o
|
||||
@-rm -f *.d
|
||||
@-rm -f gdbus/*.o
|
||||
@-rm -f gdbus/*.d
|
||||
|
||||
%.c.o: %.c
|
||||
%.c.o : %.c %.c.d
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c $*.c -o $@
|
||||
|
||||
%.c.d: %.c
|
||||
$(CC) -MM $(CFLAGS) $(CPPFLAGS) $*.c | sed -e "s/\.o/\.c.o/" > $*.c.d
|
||||
|
||||
.PRECIOUS: %.c.d
|
||||
|
||||
include $(wildcard $(patsubst %c.o,%c.d,$(MONITOR_OBJS)))
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
# Kismet Linux Bluetooth
|
||||
|
||||
Uses the bluez management socket API to initiate scans for devices
|
||||
|
|
@ -1,933 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Copyright (C) 2017 Mike Kershaw / Dragorn
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Based on the bluez-5.46 client/ code
|
||||
Copyright (C) 2012 Intel Corporation. All rights reserved.
|
||||
|
||||
Based on the Blue-Z stack code,
|
||||
|
||||
Copyright (C) 2000-2001 Qualcomm Incorporated
|
||||
Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
|
||||
and used under the GPL2 license
|
||||
|
||||
Controls a linux bluetooth interface in bluez via dbus and hci sockets
|
||||
*/
|
||||
|
||||
/* https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/device-api.txt */
|
||||
|
||||
/* Bluetooth devices are sent as complete device records in a custom
|
||||
* capsource packet, using the bluetooth protobuf entry
|
||||
*/
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <signal.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "mgmtlib/bluetooth.h"
|
||||
#include "mgmtlib/hci.h"
|
||||
#include "mgmtlib/mgmt.h"
|
||||
|
||||
#include "linux_bt_rfkill.h"
|
||||
|
||||
#include "../simple_ringbuf_c.h"
|
||||
#include "../capture_framework.h"
|
||||
|
||||
#include "../protobuf_c/linuxbluetooth.pb-c.h"
|
||||
|
||||
/* Unique instance data passed around by capframework */
|
||||
typedef struct {
|
||||
/* Target interface */
|
||||
char *bt_interface;
|
||||
char *bt_interface_str_address;
|
||||
|
||||
/* Raw (inverse) bdaddress */
|
||||
uint8_t bt_interface_address[6];
|
||||
|
||||
/* bluez management interface socket */
|
||||
int mgmt_fd;
|
||||
unsigned int devid;
|
||||
|
||||
/* Read ringbuf */
|
||||
kis_simple_ringbuf_t *read_rbuf;
|
||||
|
||||
/* Scanning type */
|
||||
uint8_t scan_type;
|
||||
|
||||
kis_capture_handler_t *caph;
|
||||
} local_bluetooth_t;
|
||||
|
||||
#define SCAN_TYPE_BREDR (1 << BDADDR_BREDR)
|
||||
#define SCAN_TYPE_LE ((1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM))
|
||||
#define SCAN_TYPE_DUAL (SCAN_TYPE_BREDR | SCAN_TYPE_LE)
|
||||
|
||||
/* Outbound commands */
|
||||
typedef struct {
|
||||
uint16_t opcode;
|
||||
uint16_t index;
|
||||
uint16_t length;
|
||||
uint8_t param[0];
|
||||
} bluez_mgmt_command_t;
|
||||
|
||||
/* Convert an address to a string; string must hold at least 18 bytes */
|
||||
#define BDADDR_STR_LEN 18
|
||||
|
||||
static char *eir_get_name(const uint8_t *eir, uint16_t eir_len);
|
||||
static unsigned int eir_get_flags(const uint8_t *eir, uint16_t eir_len);
|
||||
void bdaddr_to_string(const uint8_t *bdaddr, char *str);
|
||||
|
||||
int cf_send_btdevice(local_bluetooth_t *localbt, struct mgmt_ev_device_found *dev) {
|
||||
KismetLinuxBluetooth__LinuxBluetoothDataReport kereport;
|
||||
KismetLinuxBluetooth__SubLinuxBluetoothDevice kebtdev;
|
||||
|
||||
struct timeval tv;
|
||||
char address[BDADDR_STR_LEN];
|
||||
char *name;
|
||||
uint16_t eirlen;
|
||||
|
||||
uint8_t *buf;
|
||||
size_t len;
|
||||
|
||||
kismet_linux_bluetooth__linux_bluetooth_data_report__init(&kereport);
|
||||
kismet_linux_bluetooth__sub_linux_bluetooth_device__init(&kebtdev);
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
/* Convert the address */
|
||||
bdaddr_to_string(dev->addr.bdaddr.b, address);
|
||||
|
||||
/* Extract the name from EIR */
|
||||
eirlen = le16toh(dev->eir_len);
|
||||
name = eir_get_name(dev->eir, eirlen);
|
||||
|
||||
kebtdev.time_sec = tv.tv_sec;
|
||||
kebtdev.time_usec = tv.tv_usec;
|
||||
kebtdev.address = address;
|
||||
kebtdev.name = name;
|
||||
kebtdev.type = dev->addr.type;
|
||||
|
||||
/* We don't get txpower or uuids currently */
|
||||
|
||||
kereport.btdevice = &kebtdev;
|
||||
|
||||
/* TODO get a GPS function from capframework and fill it in here */
|
||||
|
||||
|
||||
len = kismet_linux_bluetooth__linux_bluetooth_data_report__get_packed_size(&kereport);
|
||||
buf = (uint8_t *) malloc(len);
|
||||
|
||||
if (buf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
kismet_linux_bluetooth__linux_bluetooth_data_report__pack(&kereport, buf);
|
||||
|
||||
return cf_send_packet(localbt->caph, "LBTDATAREPORT", buf, len);
|
||||
}
|
||||
|
||||
void bdaddr_to_string(const uint8_t *bdaddr, char *str) {
|
||||
snprintf(str, 18, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
|
||||
bdaddr[5], bdaddr[4], bdaddr[3],
|
||||
bdaddr[2], bdaddr[1], bdaddr[0]);
|
||||
}
|
||||
|
||||
/* Connect to the bluez management system */
|
||||
int mgmt_connect() {
|
||||
int fd;
|
||||
struct sockaddr_hci addr;
|
||||
|
||||
if ((fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
|
||||
BTPROTO_HCI)) < 0) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.hci_family = AF_BLUETOOTH;
|
||||
addr.hci_dev = HCI_DEV_NONE;
|
||||
addr.hci_channel = HCI_CHANNEL_CONTROL;
|
||||
|
||||
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
||||
int err = -errno;
|
||||
close(fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* Write a request to the management socket ringbuffer, serviced by the
|
||||
* select() loop */
|
||||
int mgmt_write_request(int mgmt_fd, uint16_t opcode, uint16_t index,
|
||||
uint16_t length, const void *param) {
|
||||
bluez_mgmt_command_t *cmd;
|
||||
size_t pksz = sizeof(bluez_mgmt_command_t) + length;
|
||||
ssize_t written_sz;
|
||||
|
||||
if (opcode == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (length > 0 && param == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmd = (bluez_mgmt_command_t *) malloc(pksz);
|
||||
|
||||
cmd->opcode = htole16(opcode);
|
||||
cmd->index = htole16(index);
|
||||
cmd->length = htole16(length);
|
||||
|
||||
if (length != 0 && param != NULL) {
|
||||
memcpy(cmd->param, param, length);
|
||||
}
|
||||
|
||||
if ((written_sz = send(mgmt_fd, cmd, pksz, 0)) < 0) {
|
||||
fprintf(stderr, "FATAL - Failed to send to mgmt sock %d: %s\n",
|
||||
mgmt_fd, strerror(errno));
|
||||
free(cmd);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
free(cmd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Initiate finding a device */
|
||||
int cmd_start_discovery(local_bluetooth_t *localbt) {
|
||||
struct mgmt_cp_start_discovery cp;
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.type = localbt->scan_type;
|
||||
|
||||
return mgmt_write_request(localbt->mgmt_fd, MGMT_OP_START_DISCOVERY,
|
||||
localbt->devid, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
/* Enable BREDR */
|
||||
int cmd_enable_bredr(local_bluetooth_t *localbt) {
|
||||
uint8_t val = 0x01;
|
||||
|
||||
return mgmt_write_request(localbt->mgmt_fd, MGMT_OP_SET_BREDR, localbt->devid,
|
||||
sizeof(val), &val);
|
||||
}
|
||||
|
||||
/* Enable BTLE */
|
||||
int cmd_enable_btle(local_bluetooth_t *localbt) {
|
||||
uint8_t val = 0x01;
|
||||
|
||||
return mgmt_write_request(localbt->mgmt_fd, MGMT_OP_SET_LE, localbt->devid,
|
||||
sizeof(val), &val);
|
||||
}
|
||||
|
||||
/* Probe the controller */
|
||||
int cmd_get_controller_info(local_bluetooth_t *localbt) {
|
||||
return mgmt_write_request(localbt->mgmt_fd, MGMT_OP_READ_INFO, localbt->devid, 0, NULL);
|
||||
}
|
||||
|
||||
int cmd_enable_controller(local_bluetooth_t *localbt) {
|
||||
uint8_t val = 0x1;
|
||||
|
||||
return mgmt_write_request(localbt->mgmt_fd, MGMT_OP_SET_POWERED, localbt->devid,
|
||||
sizeof(val), &val);
|
||||
}
|
||||
|
||||
/* Handle controller info response */
|
||||
void resp_controller_info(local_bluetooth_t *localbt, uint8_t status, uint16_t len,
|
||||
const void *param) {
|
||||
const struct mgmt_rp_read_info *rp = (struct mgmt_rp_read_info *) param;
|
||||
char bdaddr[BDADDR_STR_LEN];
|
||||
|
||||
uint32_t current, supported;
|
||||
|
||||
if (len < sizeof(struct mgmt_rp_read_info)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bdaddr_to_string(rp->bdaddr.b, bdaddr);
|
||||
|
||||
current = le32toh(rp->current_settings);
|
||||
supported = le32toh(rp->supported_settings);
|
||||
|
||||
/* Figure out if we support BDR/EDR and BTLE */
|
||||
if (!(supported & MGMT_SETTING_BREDR)) {
|
||||
localbt->scan_type &= ~SCAN_TYPE_BREDR;
|
||||
}
|
||||
|
||||
if (!(supported & MGMT_SETTING_LE)) {
|
||||
localbt->scan_type &= ~SCAN_TYPE_LE;
|
||||
}
|
||||
|
||||
/* Is BREDR enabled? If not, turn it on */
|
||||
if ((supported & MGMT_SETTING_BREDR) && !(current & MGMT_SETTING_BREDR)) {
|
||||
cmd_enable_bredr(localbt);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Is BLE enabled? If not, turn it on */
|
||||
if ((supported & MGMT_SETTING_LE) && !(current & MGMT_SETTING_LE)) {
|
||||
cmd_enable_btle(localbt);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Is it currently powered? */
|
||||
if (!(current & MGMT_SETTING_POWERED)) {
|
||||
/* If the interface is off, turn it on */
|
||||
cmd_enable_controller(localbt);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the interface is on, start scanning */
|
||||
cmd_start_discovery(localbt);
|
||||
}
|
||||
|
||||
void resp_controller_power(local_bluetooth_t *localbt, uint8_t status, uint16_t len,
|
||||
const void *param) {
|
||||
uint32_t *settings = (uint32_t *) param;
|
||||
char errstr[STATUS_MAX];
|
||||
|
||||
if (len < sizeof(uint32_t)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (*settings & MGMT_SETTING_POWERED) {
|
||||
/* Initiate scanning mode */
|
||||
cmd_start_discovery(localbt);
|
||||
} else {
|
||||
snprintf(errstr, STATUS_MAX, "Interface %s failed to power on",
|
||||
localbt->bt_interface);
|
||||
cf_send_error(localbt->caph, 0, errstr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void evt_controller_discovering(local_bluetooth_t *localbt, uint16_t len, const void *param) {
|
||||
struct mgmt_ev_discovering *dsc = (struct mgmt_ev_discovering *) param;
|
||||
|
||||
if (len < sizeof(struct mgmt_ev_discovering)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dsc->discovering) {
|
||||
cmd_start_discovery(localbt);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static char *eir_get_name(const uint8_t *eir, uint16_t eir_len) {
|
||||
uint8_t parsed = 0;
|
||||
|
||||
if (eir_len < 2)
|
||||
return NULL;
|
||||
|
||||
while (parsed < eir_len - 1) {
|
||||
uint8_t field_len = eir[0];
|
||||
|
||||
if (field_len == 0)
|
||||
break;
|
||||
|
||||
parsed += field_len + 1;
|
||||
|
||||
if (parsed > eir_len)
|
||||
break;
|
||||
|
||||
/* Check for short of complete name */
|
||||
if (eir[1] == 0x09 || eir[1] == 0x08)
|
||||
return strndup((char *) &eir[2], field_len - 1);
|
||||
|
||||
eir += field_len + 1;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned int eir_get_flags(const uint8_t *eir, uint16_t eir_len) {
|
||||
uint8_t parsed = 0;
|
||||
|
||||
if (eir_len < 2)
|
||||
return 0;
|
||||
|
||||
while (parsed < eir_len - 1) {
|
||||
uint8_t field_len = eir[0];
|
||||
|
||||
if (field_len == 0)
|
||||
break;
|
||||
|
||||
parsed += field_len + 1;
|
||||
|
||||
if (parsed > eir_len)
|
||||
break;
|
||||
|
||||
/* Check for flags */
|
||||
if (eir[1] == 0x01)
|
||||
return eir[2];
|
||||
|
||||
eir += field_len + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Actual device found in scan trigger */
|
||||
void evt_device_found(local_bluetooth_t *localbt, uint16_t len, const void *param) {
|
||||
struct mgmt_ev_device_found *dev = (struct mgmt_ev_device_found *) param;
|
||||
|
||||
if (len < sizeof(struct mgmt_ev_device_found)) {
|
||||
return;
|
||||
}
|
||||
|
||||
cf_send_btdevice(localbt, dev);
|
||||
}
|
||||
|
||||
void handle_mgmt_response(local_bluetooth_t *localbt) {
|
||||
/* Top-level command */
|
||||
bluez_mgmt_command_t *evt;
|
||||
|
||||
/* Buffer loading sizes */
|
||||
size_t bufsz;
|
||||
size_t peekedsz;
|
||||
|
||||
/* Interpreted codes from response */
|
||||
uint16_t ropcode;
|
||||
uint16_t rlength;
|
||||
uint16_t rindex;
|
||||
|
||||
/* Nested records */
|
||||
struct mgmt_ev_cmd_complete *crec;
|
||||
struct mgmt_ev_cmd_status *cstat;
|
||||
|
||||
/* caph */
|
||||
char errstr[STATUS_MAX];
|
||||
|
||||
while ((bufsz = kis_simple_ringbuf_used(localbt->read_rbuf)) >=
|
||||
sizeof(bluez_mgmt_command_t)) {
|
||||
evt = (bluez_mgmt_command_t *) malloc(bufsz);
|
||||
|
||||
if ((peekedsz = kis_simple_ringbuf_peek(localbt->read_rbuf, (void *) evt, bufsz)) <
|
||||
sizeof(bluez_mgmt_command_t)) {
|
||||
free(evt);
|
||||
return;
|
||||
}
|
||||
|
||||
ropcode = le16toh(evt->opcode);
|
||||
rindex = le16toh(evt->index);
|
||||
rlength = le16toh(evt->length);
|
||||
|
||||
if (rlength + sizeof(bluez_mgmt_command_t) > peekedsz) {
|
||||
free(evt);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Consume this object from the buffer */
|
||||
kis_simple_ringbuf_read(localbt->read_rbuf, NULL,
|
||||
sizeof(bluez_mgmt_command_t) + rlength);
|
||||
|
||||
/* Ignore events not for us */
|
||||
if (rindex != localbt->devid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ropcode == MGMT_EV_CMD_COMPLETE) {
|
||||
if (rlength < sizeof(struct mgmt_ev_cmd_complete)) {
|
||||
free(evt);
|
||||
continue;
|
||||
}
|
||||
|
||||
crec = (struct mgmt_ev_cmd_complete *) evt->param;
|
||||
|
||||
ropcode = le16toh(crec->opcode);
|
||||
|
||||
/* Handle the different opcodes */
|
||||
switch (ropcode) {
|
||||
case MGMT_OP_READ_INFO:
|
||||
resp_controller_info(localbt, crec->status,
|
||||
rlength - sizeof(struct mgmt_ev_cmd_complete),
|
||||
crec->data);
|
||||
break;
|
||||
case MGMT_OP_SET_POWERED:
|
||||
resp_controller_power(localbt, crec->status,
|
||||
rlength - sizeof(struct mgmt_ev_cmd_complete),
|
||||
crec->data);
|
||||
break;
|
||||
case MGMT_OP_START_DISCOVERY:
|
||||
if (crec->status == 0x0A) {
|
||||
break;
|
||||
} else if (crec->status != 0) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"Bluetooth interface hci%u discovery failed", rindex);
|
||||
cf_send_error(localbt->caph, 0, errstr);
|
||||
}
|
||||
break;
|
||||
case MGMT_OP_SET_BREDR:
|
||||
if (crec->status != 0) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"Bluetooth interface hci%u enabling BREDR failed", rindex);
|
||||
cf_send_error(localbt->caph, 0, errstr);
|
||||
}
|
||||
|
||||
cmd_get_controller_info(localbt);
|
||||
break;
|
||||
case MGMT_OP_SET_LE:
|
||||
if (crec->status != 0) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"Bluetooth interface hci%u enabling LE failed", rindex);
|
||||
cf_send_error(localbt->caph, 0, errstr);
|
||||
}
|
||||
|
||||
cmd_get_controller_info(localbt);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (ropcode == MGMT_EV_CMD_STATUS) {
|
||||
/* fprintf(stderr, "DEBUG - command status hci%u len %u\n", rindex, rlength); */
|
||||
} else {
|
||||
switch (ropcode) {
|
||||
case MGMT_EV_DISCOVERING:
|
||||
evt_controller_discovering(localbt,
|
||||
rlength - sizeof(bluez_mgmt_command_t),
|
||||
evt->param);
|
||||
break;
|
||||
case MGMT_EV_DEVICE_FOUND:
|
||||
evt_device_found(localbt,
|
||||
rlength - sizeof(bluez_mgmt_command_t),
|
||||
evt->param);
|
||||
break;
|
||||
case MGMT_EV_INDEX_REMOVED:
|
||||
/* we only get here if rindex matches, so we know our own
|
||||
* device got removed */
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"Bluetooth interface hci%u was removed", rindex);
|
||||
cf_send_error(localbt->caph, 0, errstr);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dump the temp object */
|
||||
free(evt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int probe_callback(kis_capture_handler_t *caph, uint32_t seqno, char *definition,
|
||||
char *msg, char **uuid, KismetExternal__Command *frame,
|
||||
cf_params_interface_t **ret_interface,
|
||||
cf_params_spectrum_t **ret_spectrum) {
|
||||
|
||||
char *placeholder = NULL;
|
||||
int placeholder_len;
|
||||
char *interface;
|
||||
char errstr[STATUS_MAX];
|
||||
|
||||
*ret_spectrum = NULL;
|
||||
*ret_interface = cf_params_interface_new();
|
||||
|
||||
uint8_t hwaddr[6];
|
||||
|
||||
int hci_sock;
|
||||
int devid;
|
||||
static struct hci_dev_info di;
|
||||
|
||||
int x;
|
||||
|
||||
if ((placeholder_len = cf_parse_interface(&placeholder, definition)) <= 0) {
|
||||
snprintf(msg, STATUS_MAX, "Unable to find interface in definition");
|
||||
return 0;
|
||||
}
|
||||
|
||||
interface = strndup(placeholder, placeholder_len);
|
||||
|
||||
if (sscanf(interface, "hci%u", &devid) != 1) {
|
||||
free(interface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((hci_sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) {
|
||||
free(interface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
di.dev_id = devid;
|
||||
|
||||
if (ioctl(hci_sock, HCIGETDEVINFO, (void *) &di)) {
|
||||
free(interface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
free(interface);
|
||||
close(hci_sock);
|
||||
|
||||
for (x = 0; x < 6; x++)
|
||||
hwaddr[5 - x] = di.bdaddr.b[x];
|
||||
|
||||
/* Make a spoofed, but consistent, UUID based on the adler32 of the interface name
|
||||
* and the mac address of the device */
|
||||
if ((placeholder_len = cf_find_flag(&placeholder, "uuid", definition)) > 0) {
|
||||
*uuid = strdup(placeholder);
|
||||
} else {
|
||||
snprintf(errstr, STATUS_MAX, "%08X-0000-0000-0000-%02X%02X%02X%02X%02X%02X",
|
||||
adler32_csum((unsigned char *) "kismet_cap_linux_bluetooth",
|
||||
strlen("kismet_cap_linux_bluetooth")) & 0xFFFFFFFF,
|
||||
hwaddr[0] & 0xFF, hwaddr[1] & 0xFF, hwaddr[2] & 0xFF,
|
||||
hwaddr[3] & 0xFF, hwaddr[4] & 0xFF, hwaddr[5] & 0xFF);
|
||||
*uuid = strdup(errstr);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int list_callback(kis_capture_handler_t *caph, uint32_t seqno,
|
||||
char *msg, cf_params_list_interface_t ***interfaces) {
|
||||
DIR *devdir;
|
||||
struct dirent *devfile;
|
||||
|
||||
/* Basic list of devices */
|
||||
typedef struct bt_list {
|
||||
char *device;
|
||||
char *flags;
|
||||
struct bt_list *next;
|
||||
} bt_list_t;
|
||||
|
||||
bt_list_t *devs = NULL;
|
||||
size_t num_devs = 0;
|
||||
|
||||
unsigned int i;
|
||||
|
||||
if ((devdir = opendir("/sys/class/bluetooth/")) == NULL) {
|
||||
/* Not an error, just nothing to do */
|
||||
*interfaces = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Look at the files in the sys dir and see if they're wi-fi */
|
||||
while ((devfile = readdir(devdir)) != NULL) {
|
||||
/* AFAIK every hciX device in the /sys/class/bluetooth dir is a bluetooth
|
||||
* controller */
|
||||
unsigned int idx;
|
||||
if (sscanf(devfile->d_name, "hci%u", &idx) == 1) {
|
||||
bt_list_t *d = (bt_list_t *) malloc(sizeof(bt_list_t));
|
||||
num_devs++;
|
||||
d->device = strdup(devfile->d_name);
|
||||
d->flags = NULL;
|
||||
d->next = devs;
|
||||
devs = d;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(devdir);
|
||||
|
||||
if (num_devs == 0) {
|
||||
*interfaces = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*interfaces =
|
||||
(cf_params_list_interface_t **) malloc(sizeof(cf_params_list_interface_t *) * num_devs);
|
||||
|
||||
i = 0;
|
||||
|
||||
while (devs != NULL) {
|
||||
bt_list_t *td = devs->next;
|
||||
(*interfaces)[i] = (cf_params_list_interface_t *) malloc(sizeof(cf_params_list_interface_t));
|
||||
memset((*interfaces)[i], 0, sizeof(cf_params_list_interface_t));
|
||||
|
||||
(*interfaces)[i]->interface = devs->device;
|
||||
(*interfaces)[i]->flags = devs->flags;
|
||||
(*interfaces)[i]->hardware = strdup("linuxhci");
|
||||
|
||||
free(devs);
|
||||
devs = td;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return num_devs;
|
||||
}
|
||||
|
||||
int open_callback(kis_capture_handler_t *caph, uint32_t seqno, char *definition,
|
||||
char *msg, uint32_t *dlt, char **uuid, KismetExternal__Command *frame,
|
||||
cf_params_interface_t **ret_interface,
|
||||
cf_params_spectrum_t **ret_spectrum) {
|
||||
|
||||
char *placeholder = NULL;
|
||||
int placeholder_len;
|
||||
char *interface;
|
||||
char errstr[STATUS_MAX];
|
||||
|
||||
*ret_spectrum = NULL;
|
||||
*ret_interface = cf_params_interface_new();
|
||||
|
||||
uint8_t hwaddr[6];
|
||||
char textaddr[18];
|
||||
|
||||
int hci_sock;
|
||||
int devid;
|
||||
static struct hci_dev_info di;
|
||||
|
||||
int x;
|
||||
|
||||
local_bluetooth_t *localbt = (local_bluetooth_t *) caph->userdata;
|
||||
|
||||
if ((placeholder_len = cf_parse_interface(&placeholder, definition)) <= 0) {
|
||||
snprintf(msg, STATUS_MAX, "Unable to find interface in definition");
|
||||
return 0;
|
||||
}
|
||||
|
||||
interface = strndup(placeholder, placeholder_len);
|
||||
|
||||
if (sscanf(interface, "hci%u", &devid) != 1) {
|
||||
snprintf(msg, STATUS_MAX, "Unable to parse device id");
|
||||
free(interface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((hci_sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) {
|
||||
snprintf(msg, STATUS_MAX, "Unable to connect HCI socket: %s",
|
||||
strerror(errno));
|
||||
free(interface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
di.dev_id = devid;
|
||||
localbt->devid = devid;
|
||||
|
||||
if (ioctl(hci_sock, HCIGETDEVINFO, (void *) &di)) {
|
||||
snprintf(msg, STATUS_MAX, "Unable to get device info: %s",
|
||||
strerror(errno));
|
||||
free(interface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (localbt->bt_interface != NULL)
|
||||
free(localbt->bt_interface);
|
||||
localbt->bt_interface = strdup(interface);
|
||||
|
||||
free(interface);
|
||||
close(hci_sock);
|
||||
|
||||
for (x = 0; x < 6; x++)
|
||||
hwaddr[5 - x] = di.bdaddr.b[x];
|
||||
|
||||
/* Make a spoofed, but consistent, UUID based on the adler32 of the interface name
|
||||
* and the mac address of the device */
|
||||
if ((placeholder_len = cf_find_flag(&placeholder, "uuid", definition)) > 0) {
|
||||
*uuid = strdup(placeholder);
|
||||
} else {
|
||||
snprintf(errstr, STATUS_MAX, "%08X-0000-0000-0000-%02X%02X%02X%02X%02X%02X",
|
||||
adler32_csum((unsigned char *) "kismet_cap_linux_bluetooth",
|
||||
strlen("kismet_cap_linux_bluetooth")) & 0xFFFFFFFF,
|
||||
hwaddr[0] & 0xFF, hwaddr[1] & 0xFF, hwaddr[2] & 0xFF,
|
||||
hwaddr[3] & 0xFF, hwaddr[4] & 0xFF, hwaddr[5] & 0xFF);
|
||||
*uuid = strdup(errstr);
|
||||
}
|
||||
|
||||
snprintf(textaddr, 18, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
|
||||
di.bdaddr.b[5], di.bdaddr.b[4], di.bdaddr.b[3],
|
||||
di.bdaddr.b[2], di.bdaddr.b[1], di.bdaddr.b[0]);
|
||||
|
||||
if (localbt->bt_interface_str_address != NULL)
|
||||
free(localbt->bt_interface_str_address);
|
||||
|
||||
memcpy(localbt->bt_interface_address, di.bdaddr.b, 6);
|
||||
localbt->bt_interface_str_address = strdup(textaddr);
|
||||
|
||||
if (linux_sys_get_bt_rfkill(localbt->bt_interface, LINUX_BT_RFKILL_TYPE_HARD)) {
|
||||
snprintf(msg, STATUS_MAX, "Bluetooth interface %s is hard blocked by rfkill, "
|
||||
"check your physical radio switch", localbt->bt_interface);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (linux_sys_get_bt_rfkill(localbt->bt_interface, LINUX_BT_RFKILL_TYPE_SOFT)) {
|
||||
if (linux_sys_clear_bt_rfkill(localbt->bt_interface) < 0) {
|
||||
snprintf(msg, STATUS_MAX, "Bluetooth interface %s is soft blocked by rfkill, "
|
||||
"and we were unable to unblock it", localbt->bt_interface);
|
||||
return -1;
|
||||
} else {
|
||||
snprintf(errstr, STATUS_MAX, "Bluetooth interface %s was blocked by "
|
||||
"rfkill, activated it", localbt->bt_interface);
|
||||
cf_send_message(caph, errstr, MSGFLAG_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
(*ret_interface)->capif = strdup(localbt->bt_interface);
|
||||
(*ret_interface)->hardware = strdup("linuxhci");
|
||||
|
||||
if (localbt->mgmt_fd > 0)
|
||||
close(localbt->mgmt_fd);
|
||||
|
||||
if ((localbt->mgmt_fd = mgmt_connect()) < 0) {
|
||||
snprintf(errstr, STATUS_MAX, "Could not connect to kernel bluez management socket: %s",
|
||||
strerror(-(localbt->mgmt_fd)));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set up our ringbuffers */
|
||||
if (localbt->read_rbuf)
|
||||
kis_simple_ringbuf_free(localbt->read_rbuf);
|
||||
|
||||
localbt->read_rbuf = kis_simple_ringbuf_create(4096);
|
||||
|
||||
if (localbt->read_rbuf == NULL) {
|
||||
snprintf(errstr, STATUS_MAX, "Could not allocate ringbuffers");
|
||||
close(localbt->mgmt_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmd_get_controller_info(localbt);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Run a standard glib mainloop inside the capture thread */
|
||||
void capture_thread(kis_capture_handler_t *caph) {
|
||||
local_bluetooth_t *localbt = (local_bluetooth_t *) caph->userdata;
|
||||
|
||||
/* Ringbuffer and select mgmt stuff */
|
||||
fd_set rset;
|
||||
struct timeval tm;
|
||||
char errstr[STATUS_MAX];
|
||||
|
||||
while (1) {
|
||||
if (caph->spindown) {
|
||||
close(localbt->mgmt_fd);
|
||||
localbt->mgmt_fd = -1;
|
||||
|
||||
kis_simple_ringbuf_free(localbt->read_rbuf);
|
||||
localbt->read_rbuf = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
FD_ZERO(&rset);
|
||||
|
||||
tm.tv_sec = 0;
|
||||
tm.tv_usec = 100000;
|
||||
|
||||
/* Always set read buffer */
|
||||
FD_SET(localbt->mgmt_fd, &rset);
|
||||
|
||||
if (select(localbt->mgmt_fd + 1, &rset, NULL, NULL, &tm) < 0) {
|
||||
if (errno != EINTR && errno != EAGAIN) {
|
||||
fprintf(stderr, "FATAL: Select failed %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FD_ISSET(localbt->mgmt_fd, &rset)) {
|
||||
while (kis_simple_ringbuf_available(localbt->read_rbuf)) {
|
||||
ssize_t amt_read;
|
||||
size_t amt_buffered;
|
||||
uint8_t rbuf[512];
|
||||
|
||||
if ((amt_read = read(localbt->mgmt_fd, rbuf, 512)) <= 0) {
|
||||
if (errno != EINTR && errno != EAGAIN) {
|
||||
snprintf(errstr, STATUS_MAX, "Failed to read from "
|
||||
"management socket: %s", strerror(errno));
|
||||
cf_send_error(caph, 0, errstr);
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
amt_buffered = kis_simple_ringbuf_write(localbt->read_rbuf, rbuf, amt_read);
|
||||
|
||||
if ((ssize_t) amt_buffered != amt_read) {
|
||||
snprintf(errstr, STATUS_MAX, "Failed to put management data into buffer");
|
||||
cf_send_error(caph, 0, errstr);
|
||||
break;
|
||||
}
|
||||
|
||||
handle_mgmt_response(localbt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
local_bluetooth_t localbt = {
|
||||
.bt_interface = NULL,
|
||||
.bt_interface_str_address = NULL,
|
||||
.devid = 0,
|
||||
.mgmt_fd = 0,
|
||||
.read_rbuf = NULL,
|
||||
.scan_type = SCAN_TYPE_DUAL,
|
||||
.caph = NULL,
|
||||
};
|
||||
|
||||
kis_capture_handler_t *caph = cf_handler_init("linuxbluetooth");
|
||||
|
||||
if (caph == NULL) {
|
||||
fprintf(stderr, "FATAL: Could not allocate basic handler data, your system "
|
||||
"is very low on RAM or something is wrong.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
localbt.caph = caph;
|
||||
|
||||
/* Set the local data ptr */
|
||||
cf_handler_set_userdata(caph, &localbt);
|
||||
|
||||
/* Set the callback for opening */
|
||||
cf_handler_set_open_cb(caph, open_callback);
|
||||
|
||||
/* Set the callback for probing an interface */
|
||||
cf_handler_set_probe_cb(caph, probe_callback);
|
||||
|
||||
/* Set the list callback */
|
||||
cf_handler_set_listdevices_cb(caph, list_callback);
|
||||
|
||||
/* Set the capture thread */
|
||||
cf_handler_set_capture_cb(caph, capture_thread);
|
||||
|
||||
if (cf_handler_parse_opts(caph, argc, argv) < 1) {
|
||||
cf_print_help(caph, argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Support remote capture by launching the remote loop */
|
||||
cf_handler_remote_capture(caph);
|
||||
|
||||
/* Jail our ns */
|
||||
cf_jail_filesystem(caph);
|
||||
|
||||
/* Strip our privs */
|
||||
cf_drop_most_caps(caph);
|
||||
|
||||
cf_handler_loop(caph);
|
||||
|
||||
// fprintf(stderr, "debug - fell out of handler loop\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "../config.h"
|
||||
#include "linux_bt_rfkill.h"
|
||||
|
||||
#ifdef SYS_LINUX
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int linux_sys_get_bt_rfkill(const char *interface, unsigned int rfkill_type) {
|
||||
DIR *devdir;
|
||||
struct dirent *devfile;
|
||||
char dirpath[2048];
|
||||
|
||||
const char *rfkill_key = "rfkill";
|
||||
const char *hard_key = "hard";
|
||||
const char *soft_key = "soft";
|
||||
|
||||
FILE *killf;
|
||||
|
||||
int r;
|
||||
|
||||
snprintf(dirpath, 2048, "/sys/class/bluetooth/%s/", interface);
|
||||
|
||||
if ((devdir = opendir(dirpath)) == NULL)
|
||||
return -1;
|
||||
|
||||
while ((devfile = readdir(devdir)) != NULL) {
|
||||
if (strlen(devfile->d_name) < strlen(rfkill_key))
|
||||
continue;
|
||||
|
||||
if (strncmp(devfile->d_name, rfkill_key, strlen(rfkill_key)) == 0) {
|
||||
snprintf(dirpath, 2048, "/sys/class/bluetooth/%s/%s/%s",
|
||||
interface, devfile->d_name,
|
||||
rfkill_type == 0 ? hard_key : soft_key);
|
||||
|
||||
if ((killf = fopen(dirpath, "r")) == NULL) {
|
||||
closedir(devdir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((fscanf(killf, "%d", &r)) != 1) {
|
||||
closedir(devdir);
|
||||
fclose(killf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
closedir(devdir);
|
||||
fclose(killf);
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int linux_sys_clear_bt_rfkill(const char *interface) {
|
||||
DIR *devdir;
|
||||
struct dirent *devfile;
|
||||
char dirpath[2048];
|
||||
|
||||
const char *rfkill_key = "rfkill";
|
||||
|
||||
FILE *killf;
|
||||
|
||||
snprintf(dirpath, 2048, "/sys/class/bluetooth/%s/", interface);
|
||||
|
||||
if ((devdir = opendir(dirpath)) == NULL)
|
||||
return -1;
|
||||
|
||||
while ((devfile = readdir(devdir)) != NULL) {
|
||||
if (strlen(devfile->d_name) < strlen(rfkill_key))
|
||||
continue;
|
||||
|
||||
if (strncmp(devfile->d_name, rfkill_key, strlen(rfkill_key)) == 0) {
|
||||
snprintf(dirpath, 2048, "/sys/class/bluetooth/%s/%s/soft",
|
||||
interface, devfile->d_name);
|
||||
|
||||
if ((killf = fopen(dirpath, "w")) == NULL) {
|
||||
closedir(devdir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fprintf(killf, "%d\n", 0) < 0) {
|
||||
closedir(devdir);
|
||||
fclose(killf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
closedir(devdir);
|
||||
fclose(killf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_BT_RFKILL_H__
|
||||
#define __LINUX_BT_RFKILL_H__
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#ifdef HAVE_LINUX_WIRELESS
|
||||
|
||||
/* Fetch if rfkill is enabled on an interface
|
||||
*
|
||||
* This uses the /sys filesystem to query the rfkill attribute.
|
||||
*
|
||||
* rfkill_type == 0 checks hard kill
|
||||
* rfkill_type == 1 checks soft kill
|
||||
*
|
||||
* Returns:
|
||||
* -1 Error, cannot determine rfkill status
|
||||
* 0 Rfkill not enabled
|
||||
* 1 Rfkill enabled
|
||||
*/
|
||||
#define LINUX_BT_RFKILL_TYPE_HARD 0
|
||||
#define LINUX_BT_RFKILL_TYPE_SOFT 1
|
||||
int linux_sys_get_bt_rfkill(const char *interface, unsigned int rfkill_type);
|
||||
|
||||
/* Disable soft rfkill on an interface if possible, can only disable soft rfkill
|
||||
*
|
||||
* Returns:
|
||||
* -1 Error, cannot change rfkill
|
||||
* 0 Success
|
||||
*/
|
||||
int linux_sys_clear_bt_rfkill(const char *interface);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
BlueZ - Bluetooth protocol stack for Linux
|
||||
|
||||
Copyright (C) 2000-2001 Qualcomm Incorporated
|
||||
Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
@ -1,149 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2012 Intel Corporation. All rights reserved.
|
||||
* Copyright (c) 2012 Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __A2MP_H
|
||||
#define __A2MP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* A2MP Protocol */
|
||||
|
||||
/* A2MP command codes */
|
||||
|
||||
#define A2MP_COMMAND_REJ 0x01
|
||||
#define A2MP_DISCOVER_REQ 0x02
|
||||
#define A2MP_DISCOVER_RSP 0x03
|
||||
#define A2MP_CHANGE_NOTIFY 0x04
|
||||
#define A2MP_CHANGE_RSP 0x05
|
||||
#define A2MP_INFO_REQ 0x06
|
||||
#define A2MP_INFO_RSP 0x07
|
||||
#define A2MP_ASSOC_REQ 0x08
|
||||
#define A2MP_ASSOC_RSP 0x09
|
||||
#define A2MP_CREATE_REQ 0x0a
|
||||
#define A2MP_CREATE_RSP 0x0b
|
||||
#define A2MP_DISCONN_REQ 0x0c
|
||||
#define A2MP_DISCONN_RSP 0x0d
|
||||
|
||||
struct a2mp_hdr {
|
||||
uint8_t code;
|
||||
uint8_t ident;
|
||||
uint16_t len;
|
||||
} __attribute__ ((packed));
|
||||
#define A2MP_HDR_SIZE 4
|
||||
|
||||
struct a2mp_command_rej {
|
||||
uint16_t reason;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_discover_req {
|
||||
uint16_t mtu;
|
||||
uint16_t mask;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_ctrl {
|
||||
uint8_t id;
|
||||
uint8_t type;
|
||||
uint8_t status;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_discover_rsp {
|
||||
uint16_t mtu;
|
||||
uint16_t mask;
|
||||
struct a2mp_ctrl ctrl_list[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_info_req {
|
||||
uint8_t id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_info_rsp {
|
||||
uint8_t id;
|
||||
uint8_t status;
|
||||
uint32_t total_bw;
|
||||
uint32_t max_bw;
|
||||
uint32_t min_latency;
|
||||
uint16_t pal_caps;
|
||||
uint16_t assoc_size;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_assoc_req {
|
||||
uint8_t id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_assoc_rsp {
|
||||
uint8_t id;
|
||||
uint8_t status;
|
||||
uint8_t assoc_data[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_create_req {
|
||||
uint8_t local_id;
|
||||
uint8_t remote_id;
|
||||
uint8_t assoc_data[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_create_rsp {
|
||||
uint8_t local_id;
|
||||
uint8_t remote_id;
|
||||
uint8_t status;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_disconn_req {
|
||||
uint8_t local_id;
|
||||
uint8_t remote_id;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct a2mp_disconn_rsp {
|
||||
uint8_t local_id;
|
||||
uint8_t remote_id;
|
||||
uint8_t status;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define A2MP_COMMAND_NOT_RECOGNIZED 0x0000
|
||||
|
||||
/* AMP controller status */
|
||||
#define AMP_CTRL_POWERED_DOWN 0x00
|
||||
#define AMP_CTRL_BLUETOOTH_ONLY 0x01
|
||||
#define AMP_CTRL_NO_CAPACITY 0x02
|
||||
#define AMP_CTRL_LOW_CAPACITY 0x03
|
||||
#define AMP_CTRL_MEDIUM_CAPACITY 0x04
|
||||
#define AMP_CTRL_HIGH_CAPACITY 0x05
|
||||
#define AMP_CTRL_FULL_CAPACITY 0x06
|
||||
|
||||
/* A2MP response status */
|
||||
#define A2MP_STATUS_SUCCESS 0x00
|
||||
#define A2MP_STATUS_INVALID_CTRL_ID 0x01
|
||||
#define A2MP_STATUS_UNABLE_START_LINK_CREATION 0x02
|
||||
#define A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS 0x02
|
||||
#define A2MP_STATUS_COLLISION_OCCURED 0x03
|
||||
#define A2MP_STATUS_DISCONN_REQ_RECVD 0x04
|
||||
#define A2MP_STATUS_PHYS_LINK_EXISTS 0x05
|
||||
#define A2MP_STATUS_SECURITY_VIOLATION 0x06
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __A2MP_H */
|
|
@ -1,172 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2010-2011 Code Aurora Forum. All rights reserved.
|
||||
* Copyright (C) 2012 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AMP_H
|
||||
#define __AMP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define AMP_MGR_CID 0x03
|
||||
|
||||
/* AMP manager codes */
|
||||
#define AMP_COMMAND_REJ 0x01
|
||||
#define AMP_DISCOVER_REQ 0x02
|
||||
#define AMP_DISCOVER_RSP 0x03
|
||||
#define AMP_CHANGE_NOTIFY 0x04
|
||||
#define AMP_CHANGE_RSP 0x05
|
||||
#define AMP_INFO_REQ 0x06
|
||||
#define AMP_INFO_RSP 0x07
|
||||
#define AMP_ASSOC_REQ 0x08
|
||||
#define AMP_ASSOC_RSP 0x09
|
||||
#define AMP_LINK_REQ 0x0a
|
||||
#define AMP_LINK_RSP 0x0b
|
||||
#define AMP_DISCONN_REQ 0x0c
|
||||
#define AMP_DISCONN_RSP 0x0d
|
||||
|
||||
typedef struct {
|
||||
uint8_t code;
|
||||
uint8_t ident;
|
||||
uint16_t len;
|
||||
} __attribute__ ((packed)) amp_mgr_hdr;
|
||||
#define AMP_MGR_HDR_SIZE 4
|
||||
|
||||
/* AMP ASSOC structure */
|
||||
typedef struct {
|
||||
uint8_t type_id;
|
||||
uint16_t len;
|
||||
uint8_t data[0];
|
||||
} __attribute__ ((packed)) amp_assoc_tlv;
|
||||
|
||||
typedef struct {
|
||||
uint16_t reason;
|
||||
} __attribute__ ((packed)) amp_cmd_rej_parms;
|
||||
|
||||
typedef struct {
|
||||
uint16_t mtu;
|
||||
uint16_t mask;
|
||||
} __attribute__ ((packed)) amp_discover_req_parms;
|
||||
|
||||
typedef struct {
|
||||
uint16_t mtu;
|
||||
uint16_t mask;
|
||||
uint8_t controller_list[0];
|
||||
} __attribute__ ((packed)) amp_discover_rsp_parms;
|
||||
|
||||
typedef struct {
|
||||
uint8_t id;
|
||||
} __attribute__ ((packed)) amp_info_req_parms;
|
||||
|
||||
typedef struct {
|
||||
uint8_t id;
|
||||
uint8_t status;
|
||||
uint32_t total_bandwidth;
|
||||
uint32_t max_bandwidth;
|
||||
uint32_t min_latency;
|
||||
uint16_t pal_caps;
|
||||
uint16_t assoc_size;
|
||||
} __attribute__ ((packed)) amp_info_rsp_parms;
|
||||
|
||||
typedef struct {
|
||||
uint8_t id;
|
||||
uint8_t status;
|
||||
amp_assoc_tlv assoc;
|
||||
} __attribute__ ((packed)) amp_assoc_rsp_parms;
|
||||
|
||||
typedef struct {
|
||||
uint8_t local_id;
|
||||
uint8_t remote_id;
|
||||
amp_assoc_tlv assoc;
|
||||
} __attribute__ ((packed)) amp_link_req_parms;
|
||||
|
||||
typedef struct {
|
||||
uint8_t local_id;
|
||||
uint8_t remote_id;
|
||||
uint8_t status;
|
||||
} __attribute__ ((packed)) amp_link_rsp_parms;
|
||||
|
||||
typedef struct {
|
||||
uint8_t local_id;
|
||||
uint8_t remote_id;
|
||||
} __attribute__ ((packed)) amp_disconn_req_parms;
|
||||
|
||||
#define A2MP_MAC_ADDR_TYPE 1
|
||||
#define A2MP_PREF_CHANLIST_TYPE 2
|
||||
#define A2MP_CONNECTED_CHAN 3
|
||||
#define A2MP_PAL_CAP_TYPE 4
|
||||
#define A2MP_PAL_VER_INFO 5
|
||||
|
||||
struct amp_tlv {
|
||||
uint8_t type;
|
||||
uint16_t len;
|
||||
uint8_t val[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct amp_pal_ver {
|
||||
uint8_t ver;
|
||||
uint16_t company_id;
|
||||
uint16_t sub_ver;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct amp_country_triplet {
|
||||
union {
|
||||
struct {
|
||||
uint8_t first_channel;
|
||||
uint8_t num_channels;
|
||||
int8_t max_power;
|
||||
} __attribute__ ((packed)) chans;
|
||||
struct {
|
||||
uint8_t reg_extension_id;
|
||||
uint8_t reg_class;
|
||||
uint8_t coverage_class;
|
||||
} __attribute__ ((packed)) ext;
|
||||
};
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct amp_chan_list {
|
||||
uint8_t country_code[3];
|
||||
struct amp_country_triplet triplets[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define AMP_COMMAND_NOT_RECOGNIZED 0x0000
|
||||
|
||||
/* AMP controller status */
|
||||
#define AMP_CT_POWERED_DOWN 0x00
|
||||
#define AMP_CT_BLUETOOTH_ONLY 0x01
|
||||
#define AMP_CT_NO_CAPACITY 0x02
|
||||
#define AMP_CT_LOW_CAPACITY 0x03
|
||||
#define AMP_CT_MEDIUM_CAPACITY 0x04
|
||||
#define AMP_CT_HIGH_CAPACITY 0x05
|
||||
#define AMP_CT_FULL_CAPACITY 0x06
|
||||
|
||||
/* AMP response status */
|
||||
#define AMP_STATUS_SUCCESS 0x00
|
||||
#define AMP_STATUS_INVALID_CTRL_ID 0x01
|
||||
#define AMP_STATUS_UNABLE_START_LINK_CREATION 0x02
|
||||
#define AMP_STATUS_NO_PHYSICAL_LINK_EXISTS 0x02
|
||||
#define AMP_STATUS_COLLISION_OCCURED 0x03
|
||||
#define AMP_STATUS_DISCONN_REQ_RECVD 0x04
|
||||
#define AMP_STATUS_PHYS_LINK_EXISTS 0x05
|
||||
#define AMP_STATUS_SECURITY_VIOLATION 0x06
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __AMP_H */
|
|
@ -1,404 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2000-2001 Qualcomm Incorporated
|
||||
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BLUETOOTH_H
|
||||
#define __BLUETOOTH_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <endian.h>
|
||||
#include <byteswap.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#ifndef AF_BLUETOOTH
|
||||
#define AF_BLUETOOTH 31
|
||||
#define PF_BLUETOOTH AF_BLUETOOTH
|
||||
#endif
|
||||
|
||||
#define BTPROTO_L2CAP 0
|
||||
#define BTPROTO_HCI 1
|
||||
#define BTPROTO_SCO 2
|
||||
#define BTPROTO_RFCOMM 3
|
||||
#define BTPROTO_BNEP 4
|
||||
#define BTPROTO_CMTP 5
|
||||
#define BTPROTO_HIDP 6
|
||||
#define BTPROTO_AVDTP 7
|
||||
|
||||
#define SOL_HCI 0
|
||||
#define SOL_L2CAP 6
|
||||
#define SOL_SCO 17
|
||||
#define SOL_RFCOMM 18
|
||||
|
||||
#ifndef SOL_BLUETOOTH
|
||||
#define SOL_BLUETOOTH 274
|
||||
#endif
|
||||
|
||||
#define BT_SECURITY 4
|
||||
struct bt_security {
|
||||
uint8_t level;
|
||||
uint8_t key_size;
|
||||
};
|
||||
#define BT_SECURITY_SDP 0
|
||||
#define BT_SECURITY_LOW 1
|
||||
#define BT_SECURITY_MEDIUM 2
|
||||
#define BT_SECURITY_HIGH 3
|
||||
#define BT_SECURITY_FIPS 4
|
||||
|
||||
#define BT_DEFER_SETUP 7
|
||||
|
||||
#define BT_FLUSHABLE 8
|
||||
|
||||
#define BT_FLUSHABLE_OFF 0
|
||||
#define BT_FLUSHABLE_ON 1
|
||||
|
||||
#define BT_POWER 9
|
||||
struct bt_power {
|
||||
uint8_t force_active;
|
||||
};
|
||||
#define BT_POWER_FORCE_ACTIVE_OFF 0
|
||||
#define BT_POWER_FORCE_ACTIVE_ON 1
|
||||
|
||||
#define BT_CHANNEL_POLICY 10
|
||||
|
||||
/* BR/EDR only (default policy)
|
||||
* AMP controllers cannot be used.
|
||||
* Channel move requests from the remote device are denied.
|
||||
* If the L2CAP channel is currently using AMP, move the channel to BR/EDR.
|
||||
*/
|
||||
#define BT_CHANNEL_POLICY_BREDR_ONLY 0
|
||||
|
||||
/* BR/EDR Preferred
|
||||
* Allow use of AMP controllers.
|
||||
* If the L2CAP channel is currently on AMP, move it to BR/EDR.
|
||||
* Channel move requests from the remote device are allowed.
|
||||
*/
|
||||
#define BT_CHANNEL_POLICY_BREDR_PREFERRED 1
|
||||
|
||||
/* AMP Preferred
|
||||
* Allow use of AMP controllers
|
||||
* If the L2CAP channel is currently on BR/EDR and AMP controller
|
||||
* resources are available, initiate a channel move to AMP.
|
||||
* Channel move requests from the remote device are allowed.
|
||||
* If the L2CAP socket has not been connected yet, try to create
|
||||
* and configure the channel directly on an AMP controller rather
|
||||
* than BR/EDR.
|
||||
*/
|
||||
#define BT_CHANNEL_POLICY_AMP_PREFERRED 2
|
||||
|
||||
#define BT_VOICE 11
|
||||
struct bt_voice {
|
||||
uint16_t setting;
|
||||
};
|
||||
|
||||
#define BT_SNDMTU 12
|
||||
#define BT_RCVMTU 13
|
||||
|
||||
#define BT_VOICE_TRANSPARENT 0x0003
|
||||
#define BT_VOICE_CVSD_16BIT 0x0060
|
||||
|
||||
/* Connection and socket states */
|
||||
enum {
|
||||
BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */
|
||||
BT_OPEN,
|
||||
BT_BOUND,
|
||||
BT_LISTEN,
|
||||
BT_CONNECT,
|
||||
BT_CONNECT2,
|
||||
BT_CONFIG,
|
||||
BT_DISCONN,
|
||||
BT_CLOSED
|
||||
};
|
||||
|
||||
/* Byte order conversions */
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define htobs(d) (d)
|
||||
#define htobl(d) (d)
|
||||
#define htobll(d) (d)
|
||||
#define btohs(d) (d)
|
||||
#define btohl(d) (d)
|
||||
#define btohll(d) (d)
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define htobs(d) bswap_16(d)
|
||||
#define htobl(d) bswap_32(d)
|
||||
#define htobll(d) bswap_64(d)
|
||||
#define btohs(d) bswap_16(d)
|
||||
#define btohl(d) bswap_32(d)
|
||||
#define btohll(d) bswap_64(d)
|
||||
#else
|
||||
#error "Unknown byte order"
|
||||
#endif
|
||||
|
||||
/* Bluetooth unaligned access */
|
||||
#define bt_get_unaligned(ptr) \
|
||||
__extension__ ({ \
|
||||
struct __attribute__((packed)) { \
|
||||
__typeof__(*(ptr)) __v; \
|
||||
} *__p = (__typeof__(__p)) (ptr); \
|
||||
__p->__v; \
|
||||
})
|
||||
|
||||
#define bt_put_unaligned(val, ptr) \
|
||||
do { \
|
||||
struct __attribute__((packed)) { \
|
||||
__typeof__(*(ptr)) __v; \
|
||||
} *__p = (__typeof__(__p)) (ptr); \
|
||||
__p->__v = (val); \
|
||||
} while(0)
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
static inline uint64_t bt_get_le64(const void *ptr)
|
||||
{
|
||||
return bt_get_unaligned((const uint64_t *) ptr);
|
||||
}
|
||||
|
||||
static inline uint64_t bt_get_be64(const void *ptr)
|
||||
{
|
||||
return bswap_64(bt_get_unaligned((const uint64_t *) ptr));
|
||||
}
|
||||
|
||||
static inline uint32_t bt_get_le32(const void *ptr)
|
||||
{
|
||||
return bt_get_unaligned((const uint32_t *) ptr);
|
||||
}
|
||||
|
||||
static inline uint32_t bt_get_be32(const void *ptr)
|
||||
{
|
||||
return bswap_32(bt_get_unaligned((const uint32_t *) ptr));
|
||||
}
|
||||
|
||||
static inline uint16_t bt_get_le16(const void *ptr)
|
||||
{
|
||||
return bt_get_unaligned((const uint16_t *) ptr);
|
||||
}
|
||||
|
||||
static inline uint16_t bt_get_be16(const void *ptr)
|
||||
{
|
||||
return bswap_16(bt_get_unaligned((const uint16_t *) ptr));
|
||||
}
|
||||
|
||||
static inline void bt_put_le64(uint64_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(val, (uint64_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_be64(uint64_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(bswap_64(val), (uint64_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_le32(uint32_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(val, (uint32_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_be32(uint32_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(bswap_32(val), (uint32_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_le16(uint16_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(val, (uint16_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_be16(uint16_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(bswap_16(val), (uint16_t *) ptr);
|
||||
}
|
||||
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
static inline uint64_t bt_get_le64(const void *ptr)
|
||||
{
|
||||
return bswap_64(bt_get_unaligned((const uint64_t *) ptr));
|
||||
}
|
||||
|
||||
static inline uint64_t bt_get_be64(const void *ptr)
|
||||
{
|
||||
return bt_get_unaligned((const uint64_t *) ptr);
|
||||
}
|
||||
|
||||
static inline uint32_t bt_get_le32(const void *ptr)
|
||||
{
|
||||
return bswap_32(bt_get_unaligned((const uint32_t *) ptr));
|
||||
}
|
||||
|
||||
static inline uint32_t bt_get_be32(const void *ptr)
|
||||
{
|
||||
return bt_get_unaligned((const uint32_t *) ptr);
|
||||
}
|
||||
|
||||
static inline uint16_t bt_get_le16(const void *ptr)
|
||||
{
|
||||
return bswap_16(bt_get_unaligned((const uint16_t *) ptr));
|
||||
}
|
||||
|
||||
static inline uint16_t bt_get_be16(const void *ptr)
|
||||
{
|
||||
return bt_get_unaligned((const uint16_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_le64(uint64_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(bswap_64(val), (uint64_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_be64(uint64_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(val, (uint64_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_le32(uint32_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(bswap_32(val), (uint32_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_be32(uint32_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(val, (uint32_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_le16(uint16_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(bswap_16(val), (uint16_t *) ptr);
|
||||
}
|
||||
|
||||
static inline void bt_put_be16(uint16_t val, const void *ptr)
|
||||
{
|
||||
bt_put_unaligned(val, (uint16_t *) ptr);
|
||||
}
|
||||
#else
|
||||
#error "Unknown byte order"
|
||||
#endif
|
||||
|
||||
/* BD Address */
|
||||
typedef struct {
|
||||
uint8_t b[6];
|
||||
} __attribute__((packed)) bdaddr_t;
|
||||
|
||||
/* BD Address type */
|
||||
#define BDADDR_BREDR 0x00
|
||||
#define BDADDR_LE_PUBLIC 0x01
|
||||
#define BDADDR_LE_RANDOM 0x02
|
||||
|
||||
#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
|
||||
#define BDADDR_ALL (&(bdaddr_t) {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}})
|
||||
#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
|
||||
|
||||
/* Copy, swap, convert BD Address */
|
||||
static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t *ba2)
|
||||
{
|
||||
return memcmp(ba1, ba2, sizeof(bdaddr_t));
|
||||
}
|
||||
static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(bdaddr_t));
|
||||
}
|
||||
|
||||
void baswap(bdaddr_t *dst, const bdaddr_t *src);
|
||||
bdaddr_t *strtoba(const char *str);
|
||||
char *batostr(const bdaddr_t *ba);
|
||||
int ba2str(const bdaddr_t *ba, char *str);
|
||||
int str2ba(const char *str, bdaddr_t *ba);
|
||||
int ba2oui(const bdaddr_t *ba, char *oui);
|
||||
int bachk(const char *str);
|
||||
|
||||
int baprintf(const char *format, ...);
|
||||
int bafprintf(FILE *stream, const char *format, ...);
|
||||
int basprintf(char *str, const char *format, ...);
|
||||
int basnprintf(char *str, size_t size, const char *format, ...);
|
||||
|
||||
void *bt_malloc(size_t size);
|
||||
void bt_free(void *ptr);
|
||||
|
||||
int bt_error(uint16_t code);
|
||||
const char *bt_compidtostr(int id);
|
||||
|
||||
typedef struct {
|
||||
uint8_t data[16];
|
||||
} uint128_t;
|
||||
|
||||
static inline void bswap_128(const void *src, void *dst)
|
||||
{
|
||||
const uint8_t *s = (const uint8_t *) src;
|
||||
uint8_t *d = (uint8_t *) dst;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
d[15 - i] = s[i];
|
||||
}
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
|
||||
#define ntoh64(x) (x)
|
||||
|
||||
static inline void ntoh128(const uint128_t *src, uint128_t *dst)
|
||||
{
|
||||
memcpy(dst, src, sizeof(uint128_t));
|
||||
}
|
||||
|
||||
static inline void btoh128(const uint128_t *src, uint128_t *dst)
|
||||
{
|
||||
bswap_128(src, dst);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline uint64_t ntoh64(uint64_t n)
|
||||
{
|
||||
uint64_t h;
|
||||
uint64_t tmp = ntohl(n & 0x00000000ffffffff);
|
||||
|
||||
h = ntohl(n >> 32);
|
||||
h |= tmp << 32;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
static inline void ntoh128(const uint128_t *src, uint128_t *dst)
|
||||
{
|
||||
bswap_128(src, dst);
|
||||
}
|
||||
|
||||
static inline void btoh128(const uint128_t *src, uint128_t *dst)
|
||||
{
|
||||
memcpy(dst, src, sizeof(uint128_t));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define hton64(x) ntoh64(x)
|
||||
#define hton128(x, y) ntoh128(x, y)
|
||||
#define htob128(x, y) btoh128(x, y)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __BLUETOOTH_H */
|
|
@ -1,162 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BNEP_H
|
||||
#define __BNEP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <bluetooth/bluetooth.h>
|
||||
|
||||
#ifndef ETH_ALEN
|
||||
#define ETH_ALEN 6 /* from <net/ethernet.h> */
|
||||
#endif
|
||||
|
||||
/* BNEP UUIDs */
|
||||
#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB
|
||||
#define BNEP_UUID16 0x02
|
||||
#define BNEP_UUID32 0x04
|
||||
#define BNEP_UUID128 0x16
|
||||
|
||||
#define BNEP_SVC_PANU 0x1115
|
||||
#define BNEP_SVC_NAP 0x1116
|
||||
#define BNEP_SVC_GN 0x1117
|
||||
|
||||
/* BNEP packet types */
|
||||
#define BNEP_GENERAL 0x00
|
||||
#define BNEP_CONTROL 0x01
|
||||
#define BNEP_COMPRESSED 0x02
|
||||
#define BNEP_COMPRESSED_SRC_ONLY 0x03
|
||||
#define BNEP_COMPRESSED_DST_ONLY 0x04
|
||||
|
||||
/* BNEP control types */
|
||||
#define BNEP_CMD_NOT_UNDERSTOOD 0x00
|
||||
#define BNEP_SETUP_CONN_REQ 0x01
|
||||
#define BNEP_SETUP_CONN_RSP 0x02
|
||||
#define BNEP_FILTER_NET_TYPE_SET 0x03
|
||||
#define BNEP_FILTER_NET_TYPE_RSP 0x04
|
||||
#define BNEP_FILTER_MULT_ADDR_SET 0x05
|
||||
#define BNEP_FILTER_MULT_ADDR_RSP 0x06
|
||||
|
||||
/* BNEP response messages */
|
||||
#define BNEP_SUCCESS 0x00
|
||||
|
||||
#define BNEP_CONN_INVALID_DST 0x01
|
||||
#define BNEP_CONN_INVALID_SRC 0x02
|
||||
#define BNEP_CONN_INVALID_SVC 0x03
|
||||
#define BNEP_CONN_NOT_ALLOWED 0x04
|
||||
|
||||
#define BNEP_FILTER_UNSUPPORTED_REQ 0x01
|
||||
#define BNEP_FILTER_INVALID_RANGE 0x02
|
||||
#define BNEP_FILTER_INVALID_MCADDR 0x02
|
||||
#define BNEP_FILTER_LIMIT_REACHED 0x03
|
||||
#define BNEP_FILTER_DENIED_SECURITY 0x04
|
||||
|
||||
/* L2CAP settings */
|
||||
#define BNEP_MTU 1691
|
||||
#define BNEP_FLUSH_TO 0xffff
|
||||
#define BNEP_CONNECT_TO 15
|
||||
#define BNEP_FILTER_TO 15
|
||||
|
||||
#ifndef BNEP_PSM
|
||||
#define BNEP_PSM 0x0f
|
||||
#endif
|
||||
|
||||
/* BNEP headers */
|
||||
#define BNEP_TYPE_MASK 0x7f
|
||||
#define BNEP_EXT_HEADER 0x80
|
||||
|
||||
struct bnep_setup_conn_req {
|
||||
uint8_t type;
|
||||
uint8_t ctrl;
|
||||
uint8_t uuid_size;
|
||||
uint8_t service[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bnep_set_filter_req {
|
||||
uint8_t type;
|
||||
uint8_t ctrl;
|
||||
uint16_t len;
|
||||
uint8_t list[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bnep_ctrl_cmd_not_understood_cmd {
|
||||
uint8_t type;
|
||||
uint8_t ctrl;
|
||||
uint8_t unkn_ctrl;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bnep_control_rsp {
|
||||
uint8_t type;
|
||||
uint8_t ctrl;
|
||||
uint16_t resp;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bnep_ext_hdr {
|
||||
uint8_t type;
|
||||
uint8_t len;
|
||||
uint8_t data[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* BNEP ioctl defines */
|
||||
#define BNEPCONNADD _IOW('B', 200, int)
|
||||
#define BNEPCONNDEL _IOW('B', 201, int)
|
||||
#define BNEPGETCONNLIST _IOR('B', 210, int)
|
||||
#define BNEPGETCONNINFO _IOR('B', 211, int)
|
||||
#define BNEPGETSUPPFEAT _IOR('B', 212, int)
|
||||
|
||||
#define BNEP_SETUP_RESPONSE 0
|
||||
|
||||
struct bnep_connadd_req {
|
||||
int sock; /* Connected socket */
|
||||
uint32_t flags;
|
||||
uint16_t role;
|
||||
char device[16]; /* Name of the Ethernet device */
|
||||
};
|
||||
|
||||
struct bnep_conndel_req {
|
||||
uint32_t flags;
|
||||
uint8_t dst[ETH_ALEN];
|
||||
};
|
||||
|
||||
struct bnep_conninfo {
|
||||
uint32_t flags;
|
||||
uint16_t role;
|
||||
uint16_t state;
|
||||
uint8_t dst[ETH_ALEN];
|
||||
char device[16];
|
||||
};
|
||||
|
||||
struct bnep_connlist_req {
|
||||
uint32_t cnum;
|
||||
struct bnep_conninfo *ci;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __BNEP_H */
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __CMTP_H
|
||||
#define __CMTP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* CMTP defaults */
|
||||
#define CMTP_MINIMUM_MTU 152
|
||||
#define CMTP_DEFAULT_MTU 672
|
||||
|
||||
/* CMTP ioctl defines */
|
||||
#define CMTPCONNADD _IOW('C', 200, int)
|
||||
#define CMTPCONNDEL _IOW('C', 201, int)
|
||||
#define CMTPGETCONNLIST _IOR('C', 210, int)
|
||||
#define CMTPGETCONNINFO _IOR('C', 211, int)
|
||||
|
||||
#define CMTP_LOOPBACK 0
|
||||
|
||||
struct cmtp_connadd_req {
|
||||
int sock; /* Connected socket */
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
struct cmtp_conndel_req {
|
||||
bdaddr_t bdaddr;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
struct cmtp_conninfo {
|
||||
bdaddr_t bdaddr;
|
||||
uint32_t flags;
|
||||
uint16_t state;
|
||||
int num;
|
||||
};
|
||||
|
||||
struct cmtp_connlist_req {
|
||||
uint32_t cnum;
|
||||
struct cmtp_conninfo *ci;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __CMTP_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,242 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2000-2001 Qualcomm Incorporated
|
||||
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __HCI_LIB_H
|
||||
#define __HCI_LIB_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct hci_request {
|
||||
uint16_t ogf;
|
||||
uint16_t ocf;
|
||||
int event;
|
||||
void *cparam;
|
||||
int clen;
|
||||
void *rparam;
|
||||
int rlen;
|
||||
};
|
||||
|
||||
struct hci_version {
|
||||
uint16_t manufacturer;
|
||||
uint8_t hci_ver;
|
||||
uint16_t hci_rev;
|
||||
uint8_t lmp_ver;
|
||||
uint16_t lmp_subver;
|
||||
};
|
||||
|
||||
int hci_open_dev(int dev_id);
|
||||
int hci_close_dev(int dd);
|
||||
int hci_send_cmd(int dd, uint16_t ogf, uint16_t ocf, uint8_t plen, void *param);
|
||||
int hci_send_req(int dd, struct hci_request *req, int timeout);
|
||||
|
||||
int hci_create_connection(int dd, const bdaddr_t *bdaddr, uint16_t ptype, uint16_t clkoffset, uint8_t rswitch, uint16_t *handle, int to);
|
||||
int hci_disconnect(int dd, uint16_t handle, uint8_t reason, int to);
|
||||
|
||||
int hci_inquiry(int dev_id, int len, int num_rsp, const uint8_t *lap, inquiry_info **ii, long flags);
|
||||
int hci_devinfo(int dev_id, struct hci_dev_info *di);
|
||||
int hci_devba(int dev_id, bdaddr_t *bdaddr);
|
||||
int hci_devid(const char *str);
|
||||
|
||||
int hci_read_local_name(int dd, int len, char *name, int to);
|
||||
int hci_write_local_name(int dd, const char *name, int to);
|
||||
int hci_read_remote_name(int dd, const bdaddr_t *bdaddr, int len, char *name, int to);
|
||||
int hci_read_remote_name_with_clock_offset(int dd, const bdaddr_t *bdaddr, uint8_t pscan_rep_mode, uint16_t clkoffset, int len, char *name, int to);
|
||||
int hci_read_remote_name_cancel(int dd, const bdaddr_t *bdaddr, int to);
|
||||
int hci_read_remote_version(int dd, uint16_t handle, struct hci_version *ver, int to);
|
||||
int hci_read_remote_features(int dd, uint16_t handle, uint8_t *features, int to);
|
||||
int hci_read_remote_ext_features(int dd, uint16_t handle, uint8_t page, uint8_t *max_page, uint8_t *features, int to);
|
||||
int hci_read_clock_offset(int dd, uint16_t handle, uint16_t *clkoffset, int to);
|
||||
int hci_read_local_version(int dd, struct hci_version *ver, int to);
|
||||
int hci_read_local_commands(int dd, uint8_t *commands, int to);
|
||||
int hci_read_local_features(int dd, uint8_t *features, int to);
|
||||
int hci_read_local_ext_features(int dd, uint8_t page, uint8_t *max_page, uint8_t *features, int to);
|
||||
int hci_read_bd_addr(int dd, bdaddr_t *bdaddr, int to);
|
||||
int hci_read_class_of_dev(int dd, uint8_t *cls, int to);
|
||||
int hci_write_class_of_dev(int dd, uint32_t cls, int to);
|
||||
int hci_read_voice_setting(int dd, uint16_t *vs, int to);
|
||||
int hci_write_voice_setting(int dd, uint16_t vs, int to);
|
||||
int hci_read_current_iac_lap(int dd, uint8_t *num_iac, uint8_t *lap, int to);
|
||||
int hci_write_current_iac_lap(int dd, uint8_t num_iac, uint8_t *lap, int to);
|
||||
int hci_read_stored_link_key(int dd, bdaddr_t *bdaddr, uint8_t all, int to);
|
||||
int hci_write_stored_link_key(int dd, bdaddr_t *bdaddr, uint8_t *key, int to);
|
||||
int hci_delete_stored_link_key(int dd, bdaddr_t *bdaddr, uint8_t all, int to);
|
||||
int hci_authenticate_link(int dd, uint16_t handle, int to);
|
||||
int hci_encrypt_link(int dd, uint16_t handle, uint8_t encrypt, int to);
|
||||
int hci_change_link_key(int dd, uint16_t handle, int to);
|
||||
int hci_switch_role(int dd, bdaddr_t *bdaddr, uint8_t role, int to);
|
||||
int hci_park_mode(int dd, uint16_t handle, uint16_t max_interval, uint16_t min_interval, int to);
|
||||
int hci_exit_park_mode(int dd, uint16_t handle, int to);
|
||||
int hci_read_inquiry_scan_type(int dd, uint8_t *type, int to);
|
||||
int hci_write_inquiry_scan_type(int dd, uint8_t type, int to);
|
||||
int hci_read_inquiry_mode(int dd, uint8_t *mode, int to);
|
||||
int hci_write_inquiry_mode(int dd, uint8_t mode, int to);
|
||||
int hci_read_afh_mode(int dd, uint8_t *mode, int to);
|
||||
int hci_write_afh_mode(int dd, uint8_t mode, int to);
|
||||
int hci_read_ext_inquiry_response(int dd, uint8_t *fec, uint8_t *data, int to);
|
||||
int hci_write_ext_inquiry_response(int dd, uint8_t fec, uint8_t *data, int to);
|
||||
int hci_read_simple_pairing_mode(int dd, uint8_t *mode, int to);
|
||||
int hci_write_simple_pairing_mode(int dd, uint8_t mode, int to);
|
||||
int hci_read_local_oob_data(int dd, uint8_t *hash, uint8_t *randomizer, int to);
|
||||
int hci_read_inq_response_tx_power_level(int dd, int8_t *level, int to);
|
||||
int hci_read_inquiry_transmit_power_level(int dd, int8_t *level, int to);
|
||||
int hci_write_inquiry_transmit_power_level(int dd, int8_t level, int to);
|
||||
int hci_read_transmit_power_level(int dd, uint16_t handle, uint8_t type, int8_t *level, int to);
|
||||
int hci_read_link_policy(int dd, uint16_t handle, uint16_t *policy, int to);
|
||||
int hci_write_link_policy(int dd, uint16_t handle, uint16_t policy, int to);
|
||||
int hci_read_link_supervision_timeout(int dd, uint16_t handle, uint16_t *timeout, int to);
|
||||
int hci_write_link_supervision_timeout(int dd, uint16_t handle, uint16_t timeout, int to);
|
||||
int hci_set_afh_classification(int dd, uint8_t *map, int to);
|
||||
int hci_read_link_quality(int dd, uint16_t handle, uint8_t *link_quality, int to);
|
||||
int hci_read_rssi(int dd, uint16_t handle, int8_t *rssi, int to);
|
||||
int hci_read_afh_map(int dd, uint16_t handle, uint8_t *mode, uint8_t *map, int to);
|
||||
int hci_read_clock(int dd, uint16_t handle, uint8_t which, uint32_t *clock, uint16_t *accuracy, int to);
|
||||
|
||||
int hci_le_set_scan_enable(int dev_id, uint8_t enable, uint8_t filter_dup, int to);
|
||||
int hci_le_set_scan_parameters(int dev_id, uint8_t type, uint16_t interval,
|
||||
uint16_t window, uint8_t own_type,
|
||||
uint8_t filter, int to);
|
||||
int hci_le_set_advertise_enable(int dev_id, uint8_t enable, int to);
|
||||
int hci_le_create_conn(int dd, uint16_t interval, uint16_t window,
|
||||
uint8_t initiator_filter, uint8_t peer_bdaddr_type,
|
||||
bdaddr_t peer_bdaddr, uint8_t own_bdaddr_type,
|
||||
uint16_t min_interval, uint16_t max_interval,
|
||||
uint16_t latency, uint16_t supervision_timeout,
|
||||
uint16_t min_ce_length, uint16_t max_ce_length,
|
||||
uint16_t *handle, int to);
|
||||
int hci_le_conn_update(int dd, uint16_t handle, uint16_t min_interval,
|
||||
uint16_t max_interval, uint16_t latency,
|
||||
uint16_t supervision_timeout, int to);
|
||||
int hci_le_add_white_list(int dd, const bdaddr_t *bdaddr, uint8_t type, int to);
|
||||
int hci_le_rm_white_list(int dd, const bdaddr_t *bdaddr, uint8_t type, int to);
|
||||
int hci_le_read_white_list_size(int dd, uint8_t *size, int to);
|
||||
int hci_le_clear_white_list(int dd, int to);
|
||||
int hci_le_add_resolving_list(int dd, const bdaddr_t *bdaddr, uint8_t type,
|
||||
uint8_t *peer_irk, uint8_t *local_irk, int to);
|
||||
int hci_le_rm_resolving_list(int dd, const bdaddr_t *bdaddr, uint8_t type, int to);
|
||||
int hci_le_clear_resolving_list(int dd, int to);
|
||||
int hci_le_read_resolving_list_size(int dd, uint8_t *size, int to);
|
||||
int hci_le_set_address_resolution_enable(int dev_id, uint8_t enable, int to);
|
||||
int hci_le_read_remote_features(int dd, uint16_t handle, uint8_t *features, int to);
|
||||
|
||||
int hci_for_each_dev(int flag, int(*func)(int dd, int dev_id, long arg), long arg);
|
||||
int hci_get_route(bdaddr_t *bdaddr);
|
||||
|
||||
char *hci_bustostr(int bus);
|
||||
char *hci_typetostr(int type);
|
||||
char *hci_dtypetostr(int type);
|
||||
char *hci_dflagstostr(uint32_t flags);
|
||||
char *hci_ptypetostr(unsigned int ptype);
|
||||
int hci_strtoptype(char *str, unsigned int *val);
|
||||
char *hci_scoptypetostr(unsigned int ptype);
|
||||
int hci_strtoscoptype(char *str, unsigned int *val);
|
||||
char *hci_lptostr(unsigned int ptype);
|
||||
int hci_strtolp(char *str, unsigned int *val);
|
||||
char *hci_lmtostr(unsigned int ptype);
|
||||
int hci_strtolm(char *str, unsigned int *val);
|
||||
|
||||
char *hci_cmdtostr(unsigned int cmd);
|
||||
char *hci_commandstostr(uint8_t *commands, char *pref, int width);
|
||||
|
||||
char *hci_vertostr(unsigned int ver);
|
||||
int hci_strtover(char *str, unsigned int *ver);
|
||||
char *lmp_vertostr(unsigned int ver);
|
||||
int lmp_strtover(char *str, unsigned int *ver);
|
||||
char *pal_vertostr(unsigned int ver);
|
||||
int pal_strtover(char *str, unsigned int *ver);
|
||||
|
||||
char *lmp_featurestostr(uint8_t *features, char *pref, int width);
|
||||
|
||||
static inline void hci_set_bit(int nr, void *addr)
|
||||
{
|
||||
*((uint32_t *) addr + (nr >> 5)) |= (1 << (nr & 31));
|
||||
}
|
||||
|
||||
static inline void hci_clear_bit(int nr, void *addr)
|
||||
{
|
||||
*((uint32_t *) addr + (nr >> 5)) &= ~(1 << (nr & 31));
|
||||
}
|
||||
|
||||
static inline int hci_test_bit(int nr, void *addr)
|
||||
{
|
||||
return *((uint32_t *) addr + (nr >> 5)) & (1 << (nr & 31));
|
||||
}
|
||||
|
||||
/* HCI filter tools */
|
||||
static inline void hci_filter_clear(struct hci_filter *f)
|
||||
{
|
||||
memset(f, 0, sizeof(*f));
|
||||
}
|
||||
static inline void hci_filter_set_ptype(int t, struct hci_filter *f)
|
||||
{
|
||||
hci_set_bit((t == HCI_VENDOR_PKT) ? 0 : (t & HCI_FLT_TYPE_BITS), &f->type_mask);
|
||||
}
|
||||
static inline void hci_filter_clear_ptype(int t, struct hci_filter *f)
|
||||
{
|
||||
hci_clear_bit((t == HCI_VENDOR_PKT) ? 0 : (t & HCI_FLT_TYPE_BITS), &f->type_mask);
|
||||
}
|
||||
static inline int hci_filter_test_ptype(int t, struct hci_filter *f)
|
||||
{
|
||||
return hci_test_bit((t == HCI_VENDOR_PKT) ? 0 : (t & HCI_FLT_TYPE_BITS), &f->type_mask);
|
||||
}
|
||||
static inline void hci_filter_all_ptypes(struct hci_filter *f)
|
||||
{
|
||||
memset((void *) &f->type_mask, 0xff, sizeof(f->type_mask));
|
||||
}
|
||||
static inline void hci_filter_set_event(int e, struct hci_filter *f)
|
||||
{
|
||||
hci_set_bit((e & HCI_FLT_EVENT_BITS), &f->event_mask);
|
||||
}
|
||||
static inline void hci_filter_clear_event(int e, struct hci_filter *f)
|
||||
{
|
||||
hci_clear_bit((e & HCI_FLT_EVENT_BITS), &f->event_mask);
|
||||
}
|
||||
static inline int hci_filter_test_event(int e, struct hci_filter *f)
|
||||
{
|
||||
return hci_test_bit((e & HCI_FLT_EVENT_BITS), &f->event_mask);
|
||||
}
|
||||
static inline void hci_filter_all_events(struct hci_filter *f)
|
||||
{
|
||||
memset((void *) f->event_mask, 0xff, sizeof(f->event_mask));
|
||||
}
|
||||
static inline void hci_filter_set_opcode(int opcode, struct hci_filter *f)
|
||||
{
|
||||
f->opcode = opcode;
|
||||
}
|
||||
static inline void hci_filter_clear_opcode(struct hci_filter *f)
|
||||
{
|
||||
f->opcode = 0;
|
||||
}
|
||||
static inline int hci_filter_test_opcode(int opcode, struct hci_filter *f)
|
||||
{
|
||||
return (f->opcode == opcode);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HCI_LIB_H */
|
|
@ -1,85 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __HIDP_H
|
||||
#define __HIDP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* HIDP defaults */
|
||||
#define HIDP_MINIMUM_MTU 48
|
||||
#define HIDP_DEFAULT_MTU 48
|
||||
|
||||
/* HIDP ioctl defines */
|
||||
#define HIDPCONNADD _IOW('H', 200, int)
|
||||
#define HIDPCONNDEL _IOW('H', 201, int)
|
||||
#define HIDPGETCONNLIST _IOR('H', 210, int)
|
||||
#define HIDPGETCONNINFO _IOR('H', 211, int)
|
||||
|
||||
#define HIDP_VIRTUAL_CABLE_UNPLUG 0
|
||||
#define HIDP_BOOT_PROTOCOL_MODE 1
|
||||
#define HIDP_BLUETOOTH_VENDOR_ID 9
|
||||
|
||||
struct hidp_connadd_req {
|
||||
int ctrl_sock; /* Connected control socket */
|
||||
int intr_sock; /* Connected interrupt socket */
|
||||
uint16_t parser; /* Parser version */
|
||||
uint16_t rd_size; /* Report descriptor size */
|
||||
uint8_t *rd_data; /* Report descriptor data */
|
||||
uint8_t country;
|
||||
uint8_t subclass;
|
||||
uint16_t vendor;
|
||||
uint16_t product;
|
||||
uint16_t version;
|
||||
uint32_t flags;
|
||||
uint32_t idle_to;
|
||||
char name[128]; /* Device name */
|
||||
};
|
||||
|
||||
struct hidp_conndel_req {
|
||||
bdaddr_t bdaddr;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
struct hidp_conninfo {
|
||||
bdaddr_t bdaddr;
|
||||
uint32_t flags;
|
||||
uint16_t state;
|
||||
uint16_t vendor;
|
||||
uint16_t product;
|
||||
uint16_t version;
|
||||
char name[128];
|
||||
};
|
||||
|
||||
struct hidp_connlist_req {
|
||||
uint32_t cnum;
|
||||
struct hidp_conninfo *ci;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HIDP_H */
|
|
@ -1,279 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2000-2001 Qualcomm Incorporated
|
||||
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
* Copyright (c) 2012 Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __L2CAP_H
|
||||
#define __L2CAP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
/* L2CAP defaults */
|
||||
#define L2CAP_DEFAULT_MTU 672
|
||||
#define L2CAP_DEFAULT_FLUSH_TO 0xFFFF
|
||||
|
||||
/* L2CAP socket address */
|
||||
struct sockaddr_l2 {
|
||||
sa_family_t l2_family;
|
||||
unsigned short l2_psm;
|
||||
bdaddr_t l2_bdaddr;
|
||||
unsigned short l2_cid;
|
||||
uint8_t l2_bdaddr_type;
|
||||
};
|
||||
|
||||
/* L2CAP socket options */
|
||||
#define L2CAP_OPTIONS 0x01
|
||||
struct l2cap_options {
|
||||
uint16_t omtu;
|
||||
uint16_t imtu;
|
||||
uint16_t flush_to;
|
||||
uint8_t mode;
|
||||
uint8_t fcs;
|
||||
uint8_t max_tx;
|
||||
uint16_t txwin_size;
|
||||
};
|
||||
|
||||
#define L2CAP_CONNINFO 0x02
|
||||
struct l2cap_conninfo {
|
||||
uint16_t hci_handle;
|
||||
uint8_t dev_class[3];
|
||||
};
|
||||
|
||||
#define L2CAP_LM 0x03
|
||||
#define L2CAP_LM_MASTER 0x0001
|
||||
#define L2CAP_LM_AUTH 0x0002
|
||||
#define L2CAP_LM_ENCRYPT 0x0004
|
||||
#define L2CAP_LM_TRUSTED 0x0008
|
||||
#define L2CAP_LM_RELIABLE 0x0010
|
||||
#define L2CAP_LM_SECURE 0x0020
|
||||
|
||||
/* L2CAP command codes */
|
||||
#define L2CAP_COMMAND_REJ 0x01
|
||||
#define L2CAP_CONN_REQ 0x02
|
||||
#define L2CAP_CONN_RSP 0x03
|
||||
#define L2CAP_CONF_REQ 0x04
|
||||
#define L2CAP_CONF_RSP 0x05
|
||||
#define L2CAP_DISCONN_REQ 0x06
|
||||
#define L2CAP_DISCONN_RSP 0x07
|
||||
#define L2CAP_ECHO_REQ 0x08
|
||||
#define L2CAP_ECHO_RSP 0x09
|
||||
#define L2CAP_INFO_REQ 0x0a
|
||||
#define L2CAP_INFO_RSP 0x0b
|
||||
#define L2CAP_CREATE_REQ 0x0c
|
||||
#define L2CAP_CREATE_RSP 0x0d
|
||||
#define L2CAP_MOVE_REQ 0x0e
|
||||
#define L2CAP_MOVE_RSP 0x0f
|
||||
#define L2CAP_MOVE_CFM 0x10
|
||||
#define L2CAP_MOVE_CFM_RSP 0x11
|
||||
|
||||
/* L2CAP extended feature mask */
|
||||
#define L2CAP_FEAT_FLOWCTL 0x00000001
|
||||
#define L2CAP_FEAT_RETRANS 0x00000002
|
||||
#define L2CAP_FEAT_BIDIR_QOS 0x00000004
|
||||
#define L2CAP_FEAT_ERTM 0x00000008
|
||||
#define L2CAP_FEAT_STREAMING 0x00000010
|
||||
#define L2CAP_FEAT_FCS 0x00000020
|
||||
#define L2CAP_FEAT_EXT_FLOW 0x00000040
|
||||
#define L2CAP_FEAT_FIXED_CHAN 0x00000080
|
||||
#define L2CAP_FEAT_EXT_WINDOW 0x00000100
|
||||
#define L2CAP_FEAT_UCD 0x00000200
|
||||
|
||||
/* L2CAP fixed channels */
|
||||
#define L2CAP_FC_L2CAP 0x02
|
||||
#define L2CAP_FC_CONNLESS 0x04
|
||||
#define L2CAP_FC_A2MP 0x08
|
||||
|
||||
/* L2CAP structures */
|
||||
typedef struct {
|
||||
uint16_t len;
|
||||
uint16_t cid;
|
||||
} __attribute__ ((packed)) l2cap_hdr;
|
||||
#define L2CAP_HDR_SIZE 4
|
||||
|
||||
typedef struct {
|
||||
uint8_t code;
|
||||
uint8_t ident;
|
||||
uint16_t len;
|
||||
} __attribute__ ((packed)) l2cap_cmd_hdr;
|
||||
#define L2CAP_CMD_HDR_SIZE 4
|
||||
|
||||
typedef struct {
|
||||
uint16_t reason;
|
||||
} __attribute__ ((packed)) l2cap_cmd_rej;
|
||||
#define L2CAP_CMD_REJ_SIZE 2
|
||||
|
||||
typedef struct {
|
||||
uint16_t psm;
|
||||
uint16_t scid;
|
||||
} __attribute__ ((packed)) l2cap_conn_req;
|
||||
#define L2CAP_CONN_REQ_SIZE 4
|
||||
|
||||
typedef struct {
|
||||
uint16_t dcid;
|
||||
uint16_t scid;
|
||||
uint16_t result;
|
||||
uint16_t status;
|
||||
} __attribute__ ((packed)) l2cap_conn_rsp;
|
||||
#define L2CAP_CONN_RSP_SIZE 8
|
||||
|
||||
/* connect result */
|
||||
#define L2CAP_CR_SUCCESS 0x0000
|
||||
#define L2CAP_CR_PEND 0x0001
|
||||
#define L2CAP_CR_BAD_PSM 0x0002
|
||||
#define L2CAP_CR_SEC_BLOCK 0x0003
|
||||
#define L2CAP_CR_NO_MEM 0x0004
|
||||
|
||||
/* connect status */
|
||||
#define L2CAP_CS_NO_INFO 0x0000
|
||||
#define L2CAP_CS_AUTHEN_PEND 0x0001
|
||||
#define L2CAP_CS_AUTHOR_PEND 0x0002
|
||||
|
||||
typedef struct {
|
||||
uint16_t dcid;
|
||||
uint16_t flags;
|
||||
uint8_t data[0];
|
||||
} __attribute__ ((packed)) l2cap_conf_req;
|
||||
#define L2CAP_CONF_REQ_SIZE 4
|
||||
|
||||
typedef struct {
|
||||
uint16_t scid;
|
||||
uint16_t flags;
|
||||
uint16_t result;
|
||||
uint8_t data[0];
|
||||
} __attribute__ ((packed)) l2cap_conf_rsp;
|
||||
#define L2CAP_CONF_RSP_SIZE 6
|
||||
|
||||
#define L2CAP_CONF_SUCCESS 0x0000
|
||||
#define L2CAP_CONF_UNACCEPT 0x0001
|
||||
#define L2CAP_CONF_REJECT 0x0002
|
||||
#define L2CAP_CONF_UNKNOWN 0x0003
|
||||
#define L2CAP_CONF_PENDING 0x0004
|
||||
#define L2CAP_CONF_EFS_REJECT 0x0005
|
||||
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
uint8_t len;
|
||||
uint8_t val[0];
|
||||
} __attribute__ ((packed)) l2cap_conf_opt;
|
||||
#define L2CAP_CONF_OPT_SIZE 2
|
||||
|
||||
#define L2CAP_CONF_MTU 0x01
|
||||
#define L2CAP_CONF_FLUSH_TO 0x02
|
||||
#define L2CAP_CONF_QOS 0x03
|
||||
#define L2CAP_CONF_RFC 0x04
|
||||
#define L2CAP_CONF_FCS 0x05
|
||||
#define L2CAP_CONF_EFS 0x06
|
||||
#define L2CAP_CONF_EWS 0x07
|
||||
|
||||
#define L2CAP_CONF_MAX_SIZE 22
|
||||
|
||||
#define L2CAP_MODE_BASIC 0x00
|
||||
#define L2CAP_MODE_RETRANS 0x01
|
||||
#define L2CAP_MODE_FLOWCTL 0x02
|
||||
#define L2CAP_MODE_ERTM 0x03
|
||||
#define L2CAP_MODE_STREAMING 0x04
|
||||
|
||||
#define L2CAP_SERVTYPE_NOTRAFFIC 0x00
|
||||
#define L2CAP_SERVTYPE_BESTEFFORT 0x01
|
||||
#define L2CAP_SERVTYPE_GUARANTEED 0x02
|
||||
|
||||
typedef struct {
|
||||
uint16_t dcid;
|
||||
uint16_t scid;
|
||||
} __attribute__ ((packed)) l2cap_disconn_req;
|
||||
#define L2CAP_DISCONN_REQ_SIZE 4
|
||||
|
||||
typedef struct {
|
||||
uint16_t dcid;
|
||||
uint16_t scid;
|
||||
} __attribute__ ((packed)) l2cap_disconn_rsp;
|
||||
#define L2CAP_DISCONN_RSP_SIZE 4
|
||||
|
||||
typedef struct {
|
||||
uint16_t type;
|
||||
} __attribute__ ((packed)) l2cap_info_req;
|
||||
#define L2CAP_INFO_REQ_SIZE 2
|
||||
|
||||
typedef struct {
|
||||
uint16_t type;
|
||||
uint16_t result;
|
||||
uint8_t data[0];
|
||||
} __attribute__ ((packed)) l2cap_info_rsp;
|
||||
#define L2CAP_INFO_RSP_SIZE 4
|
||||
|
||||
/* info type */
|
||||
#define L2CAP_IT_CL_MTU 0x0001
|
||||
#define L2CAP_IT_FEAT_MASK 0x0002
|
||||
|
||||
/* info result */
|
||||
#define L2CAP_IR_SUCCESS 0x0000
|
||||
#define L2CAP_IR_NOTSUPP 0x0001
|
||||
|
||||
typedef struct {
|
||||
uint16_t psm;
|
||||
uint16_t scid;
|
||||
uint8_t id;
|
||||
} __attribute__ ((packed)) l2cap_create_req;
|
||||
#define L2CAP_CREATE_REQ_SIZE 5
|
||||
|
||||
typedef struct {
|
||||
uint16_t dcid;
|
||||
uint16_t scid;
|
||||
uint16_t result;
|
||||
uint16_t status;
|
||||
} __attribute__ ((packed)) l2cap_create_rsp;
|
||||
#define L2CAP_CREATE_RSP_SIZE 8
|
||||
|
||||
typedef struct {
|
||||
uint16_t icid;
|
||||
uint8_t id;
|
||||
} __attribute__ ((packed)) l2cap_move_req;
|
||||
#define L2CAP_MOVE_REQ_SIZE 3
|
||||
|
||||
typedef struct {
|
||||
uint16_t icid;
|
||||
uint16_t result;
|
||||
} __attribute__ ((packed)) l2cap_move_rsp;
|
||||
#define L2CAP_MOVE_RSP_SIZE 4
|
||||
|
||||
typedef struct {
|
||||
uint16_t icid;
|
||||
uint16_t result;
|
||||
} __attribute__ ((packed)) l2cap_move_cfm;
|
||||
#define L2CAP_MOVE_CFM_SIZE 4
|
||||
|
||||
typedef struct {
|
||||
uint16_t icid;
|
||||
} __attribute__ ((packed)) l2cap_move_cfm_rsp;
|
||||
#define L2CAP_MOVE_CFM_RSP_SIZE 2
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __L2CAP_H */
|
|
@ -1,926 +0,0 @@
|
|||
/*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2010 Nokia Corporation
|
||||
* Copyright (C) 2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __packed
|
||||
#define __packed __attribute__((packed))
|
||||
#endif
|
||||
|
||||
#define MGMT_INDEX_NONE 0xFFFF
|
||||
|
||||
#define MGMT_STATUS_SUCCESS 0x00
|
||||
#define MGMT_STATUS_UNKNOWN_COMMAND 0x01
|
||||
#define MGMT_STATUS_NOT_CONNECTED 0x02
|
||||
#define MGMT_STATUS_FAILED 0x03
|
||||
#define MGMT_STATUS_CONNECT_FAILED 0x04
|
||||
#define MGMT_STATUS_AUTH_FAILED 0x05
|
||||
#define MGMT_STATUS_NOT_PAIRED 0x06
|
||||
#define MGMT_STATUS_NO_RESOURCES 0x07
|
||||
#define MGMT_STATUS_TIMEOUT 0x08
|
||||
#define MGMT_STATUS_ALREADY_CONNECTED 0x09
|
||||
#define MGMT_STATUS_BUSY 0x0a
|
||||
#define MGMT_STATUS_REJECTED 0x0b
|
||||
#define MGMT_STATUS_NOT_SUPPORTED 0x0c
|
||||
#define MGMT_STATUS_INVALID_PARAMS 0x0d
|
||||
#define MGMT_STATUS_DISCONNECTED 0x0e
|
||||
#define MGMT_STATUS_NOT_POWERED 0x0f
|
||||
#define MGMT_STATUS_CANCELLED 0x10
|
||||
#define MGMT_STATUS_INVALID_INDEX 0x11
|
||||
#define MGMT_STATUS_RFKILLED 0x12
|
||||
#define MGMT_STATUS_ALREADY_PAIRED 0x13
|
||||
#define MGMT_STATUS_PERMISSION_DENIED 0x14
|
||||
|
||||
struct mgmt_hdr {
|
||||
uint16_t opcode;
|
||||
uint16_t index;
|
||||
uint16_t len;
|
||||
} __packed;
|
||||
#define MGMT_HDR_SIZE 6
|
||||
|
||||
struct mgmt_addr_info {
|
||||
bdaddr_t bdaddr;
|
||||
uint8_t type;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_READ_VERSION 0x0001
|
||||
struct mgmt_rp_read_version {
|
||||
uint8_t version;
|
||||
uint16_t revision;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_READ_COMMANDS 0x0002
|
||||
struct mgmt_rp_read_commands {
|
||||
uint16_t num_commands;
|
||||
uint16_t num_events;
|
||||
uint16_t opcodes[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_READ_INDEX_LIST 0x0003
|
||||
struct mgmt_rp_read_index_list {
|
||||
uint16_t num_controllers;
|
||||
uint16_t index[0];
|
||||
} __packed;
|
||||
|
||||
/* Reserve one extra byte for names in management messages so that they
|
||||
* are always guaranteed to be nul-terminated */
|
||||
#define MGMT_MAX_NAME_LENGTH (248 + 1)
|
||||
#define MGMT_MAX_SHORT_NAME_LENGTH (10 + 1)
|
||||
|
||||
#define MGMT_SETTING_POWERED 0x00000001
|
||||
#define MGMT_SETTING_CONNECTABLE 0x00000002
|
||||
#define MGMT_SETTING_FAST_CONNECTABLE 0x00000004
|
||||
#define MGMT_SETTING_DISCOVERABLE 0x00000008
|
||||
#define MGMT_SETTING_BONDABLE 0x00000010
|
||||
#define MGMT_SETTING_LINK_SECURITY 0x00000020
|
||||
#define MGMT_SETTING_SSP 0x00000040
|
||||
#define MGMT_SETTING_BREDR 0x00000080
|
||||
#define MGMT_SETTING_HS 0x00000100
|
||||
#define MGMT_SETTING_LE 0x00000200
|
||||
#define MGMT_SETTING_ADVERTISING 0x00000400
|
||||
#define MGMT_SETTING_SECURE_CONN 0x00000800
|
||||
#define MGMT_SETTING_DEBUG_KEYS 0x00001000
|
||||
#define MGMT_SETTING_PRIVACY 0x00002000
|
||||
#define MGMT_SETTING_CONFIGURATION 0x00004000
|
||||
#define MGMT_SETTING_STATIC_ADDRESS 0x00008000
|
||||
|
||||
#define MGMT_OP_READ_INFO 0x0004
|
||||
struct mgmt_rp_read_info {
|
||||
bdaddr_t bdaddr;
|
||||
uint8_t version;
|
||||
uint16_t manufacturer;
|
||||
uint32_t supported_settings;
|
||||
uint32_t current_settings;
|
||||
uint8_t dev_class[3];
|
||||
uint8_t name[MGMT_MAX_NAME_LENGTH];
|
||||
uint8_t short_name[MGMT_MAX_SHORT_NAME_LENGTH];
|
||||
} __packed;
|
||||
|
||||
struct mgmt_mode {
|
||||
uint8_t val;
|
||||
} __packed;
|
||||
|
||||
struct mgmt_cod {
|
||||
uint8_t val[3];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_POWERED 0x0005
|
||||
|
||||
#define MGMT_OP_SET_DISCOVERABLE 0x0006
|
||||
struct mgmt_cp_set_discoverable {
|
||||
uint8_t val;
|
||||
uint16_t timeout;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_CONNECTABLE 0x0007
|
||||
|
||||
#define MGMT_OP_SET_FAST_CONNECTABLE 0x0008
|
||||
|
||||
#define MGMT_OP_SET_BONDABLE 0x0009
|
||||
|
||||
#define MGMT_OP_SET_LINK_SECURITY 0x000A
|
||||
|
||||
#define MGMT_OP_SET_SSP 0x000B
|
||||
|
||||
#define MGMT_OP_SET_HS 0x000C
|
||||
|
||||
#define MGMT_OP_SET_LE 0x000D
|
||||
|
||||
#define MGMT_OP_SET_DEV_CLASS 0x000E
|
||||
struct mgmt_cp_set_dev_class {
|
||||
uint8_t major;
|
||||
uint8_t minor;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_LOCAL_NAME 0x000F
|
||||
struct mgmt_cp_set_local_name {
|
||||
uint8_t name[MGMT_MAX_NAME_LENGTH];
|
||||
uint8_t short_name[MGMT_MAX_SHORT_NAME_LENGTH];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_ADD_UUID 0x0010
|
||||
struct mgmt_cp_add_uuid {
|
||||
uint8_t uuid[16];
|
||||
uint8_t svc_hint;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_REMOVE_UUID 0x0011
|
||||
struct mgmt_cp_remove_uuid {
|
||||
uint8_t uuid[16];
|
||||
} __packed;
|
||||
|
||||
struct mgmt_link_key_info {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t type;
|
||||
uint8_t val[16];
|
||||
uint8_t pin_len;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_LOAD_LINK_KEYS 0x0012
|
||||
struct mgmt_cp_load_link_keys {
|
||||
uint8_t debug_keys;
|
||||
uint16_t key_count;
|
||||
struct mgmt_link_key_info keys[0];
|
||||
} __packed;
|
||||
|
||||
struct mgmt_ltk_info {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t type;
|
||||
uint8_t master;
|
||||
uint8_t enc_size;
|
||||
uint16_t ediv;
|
||||
uint64_t rand;
|
||||
uint8_t val[16];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_LOAD_LONG_TERM_KEYS 0x0013
|
||||
struct mgmt_cp_load_long_term_keys {
|
||||
uint16_t key_count;
|
||||
struct mgmt_ltk_info keys[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_DISCONNECT 0x0014
|
||||
struct mgmt_cp_disconnect {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
struct mgmt_rp_disconnect {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_GET_CONNECTIONS 0x0015
|
||||
struct mgmt_rp_get_connections {
|
||||
uint16_t conn_count;
|
||||
struct mgmt_addr_info addr[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_PIN_CODE_REPLY 0x0016
|
||||
struct mgmt_cp_pin_code_reply {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t pin_len;
|
||||
uint8_t pin_code[16];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_PIN_CODE_NEG_REPLY 0x0017
|
||||
struct mgmt_cp_pin_code_neg_reply {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_IO_CAPABILITY 0x0018
|
||||
struct mgmt_cp_set_io_capability {
|
||||
uint8_t io_capability;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_PAIR_DEVICE 0x0019
|
||||
struct mgmt_cp_pair_device {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t io_cap;
|
||||
} __packed;
|
||||
struct mgmt_rp_pair_device {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_CANCEL_PAIR_DEVICE 0x001A
|
||||
|
||||
#define MGMT_OP_UNPAIR_DEVICE 0x001B
|
||||
struct mgmt_cp_unpair_device {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t disconnect;
|
||||
} __packed;
|
||||
struct mgmt_rp_unpair_device {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_USER_CONFIRM_REPLY 0x001C
|
||||
struct mgmt_cp_user_confirm_reply {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
struct mgmt_rp_user_confirm_reply {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x001D
|
||||
|
||||
#define MGMT_OP_USER_PASSKEY_REPLY 0x001E
|
||||
struct mgmt_cp_user_passkey_reply {
|
||||
struct mgmt_addr_info addr;
|
||||
uint32_t passkey;
|
||||
} __packed;
|
||||
struct mgmt_rp_user_passkey_reply {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_USER_PASSKEY_NEG_REPLY 0x001F
|
||||
struct mgmt_cp_user_passkey_neg_reply {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_READ_LOCAL_OOB_DATA 0x0020
|
||||
struct mgmt_rp_read_local_oob_data {
|
||||
uint8_t hash192[16];
|
||||
uint8_t rand192[16];
|
||||
uint8_t hash256[16];
|
||||
uint8_t rand256[16];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_ADD_REMOTE_OOB_DATA 0x0021
|
||||
struct mgmt_cp_add_remote_oob_data {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t hash192[16];
|
||||
uint8_t rand192[16];
|
||||
uint8_t hash256[16];
|
||||
uint8_t rand256[16];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x0022
|
||||
struct mgmt_cp_remove_remote_oob_data {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_START_DISCOVERY 0x0023
|
||||
struct mgmt_cp_start_discovery {
|
||||
uint8_t type;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_STOP_DISCOVERY 0x0024
|
||||
struct mgmt_cp_stop_discovery {
|
||||
uint8_t type;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_CONFIRM_NAME 0x0025
|
||||
struct mgmt_cp_confirm_name {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t name_known;
|
||||
} __packed;
|
||||
struct mgmt_rp_confirm_name {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_BLOCK_DEVICE 0x0026
|
||||
struct mgmt_cp_block_device {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_UNBLOCK_DEVICE 0x0027
|
||||
struct mgmt_cp_unblock_device {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_DEVICE_ID 0x0028
|
||||
struct mgmt_cp_set_device_id {
|
||||
uint16_t source;
|
||||
uint16_t vendor;
|
||||
uint16_t product;
|
||||
uint16_t version;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_ADVERTISING 0x0029
|
||||
|
||||
#define MGMT_OP_SET_BREDR 0x002A
|
||||
|
||||
#define MGMT_OP_SET_STATIC_ADDRESS 0x002B
|
||||
struct mgmt_cp_set_static_address {
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_SCAN_PARAMS 0x002C
|
||||
struct mgmt_cp_set_scan_params {
|
||||
uint16_t interval;
|
||||
uint16_t window;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_SECURE_CONN 0x002D
|
||||
|
||||
#define MGMT_OP_SET_DEBUG_KEYS 0x002E
|
||||
|
||||
struct mgmt_irk_info {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t val[16];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_PRIVACY 0x002F
|
||||
struct mgmt_cp_set_privacy {
|
||||
uint8_t privacy;
|
||||
uint8_t irk[16];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_LOAD_IRKS 0x0030
|
||||
struct mgmt_cp_load_irks {
|
||||
uint16_t irk_count;
|
||||
struct mgmt_irk_info irks[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_GET_CONN_INFO 0x0031
|
||||
struct mgmt_cp_get_conn_info {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
struct mgmt_rp_get_conn_info {
|
||||
struct mgmt_addr_info addr;
|
||||
int8_t rssi;
|
||||
int8_t tx_power;
|
||||
int8_t max_tx_power;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_GET_CLOCK_INFO 0x0032
|
||||
struct mgmt_cp_get_clock_info {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
struct mgmt_rp_get_clock_info {
|
||||
struct mgmt_addr_info addr;
|
||||
uint32_t local_clock;
|
||||
uint32_t piconet_clock;
|
||||
uint16_t accuracy;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_ADD_DEVICE 0x0033
|
||||
struct mgmt_cp_add_device {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t action;
|
||||
} __packed;
|
||||
struct mgmt_rp_add_device {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_REMOVE_DEVICE 0x0034
|
||||
struct mgmt_cp_remove_device {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
struct mgmt_rp_remove_device {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
struct mgmt_conn_param {
|
||||
struct mgmt_addr_info addr;
|
||||
uint16_t min_interval;
|
||||
uint16_t max_interval;
|
||||
uint16_t latency;
|
||||
uint16_t timeout;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_LOAD_CONN_PARAM 0x0035
|
||||
struct mgmt_cp_load_conn_param {
|
||||
uint16_t param_count;
|
||||
struct mgmt_conn_param params[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_READ_UNCONF_INDEX_LIST 0x0036
|
||||
struct mgmt_rp_read_unconf_index_list {
|
||||
uint16_t num_controllers;
|
||||
uint16_t index[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OPTION_EXTERNAL_CONFIG 0x00000001
|
||||
#define MGMT_OPTION_PUBLIC_ADDRESS 0x00000002
|
||||
|
||||
#define MGMT_OP_READ_CONFIG_INFO 0x0037
|
||||
struct mgmt_rp_read_config_info {
|
||||
uint16_t manufacturer;
|
||||
uint32_t supported_options;
|
||||
uint32_t missing_options;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_EXTERNAL_CONFIG 0x0038
|
||||
struct mgmt_cp_set_external_config {
|
||||
uint8_t config;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_PUBLIC_ADDRESS 0x0039
|
||||
struct mgmt_cp_set_public_address {
|
||||
bdaddr_t bdaddr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_START_SERVICE_DISCOVERY 0x003A
|
||||
struct mgmt_cp_start_service_discovery {
|
||||
uint8_t type;
|
||||
int8_t rssi;
|
||||
uint16_t uuid_count;
|
||||
uint8_t uuids[0][16];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_READ_LOCAL_OOB_EXT_DATA 0x003B
|
||||
struct mgmt_cp_read_local_oob_ext_data {
|
||||
uint8_t type;
|
||||
} __packed;
|
||||
struct mgmt_rp_read_local_oob_ext_data {
|
||||
uint8_t type;
|
||||
uint16_t eir_len;
|
||||
uint8_t eir[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_READ_EXT_INDEX_LIST 0x003C
|
||||
struct mgmt_rp_read_ext_index_list {
|
||||
uint16_t num_controllers;
|
||||
struct {
|
||||
uint16_t index;
|
||||
uint8_t type;
|
||||
uint8_t bus;
|
||||
} entry[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_READ_ADV_FEATURES 0x003D
|
||||
struct mgmt_rp_read_adv_features {
|
||||
uint32_t supported_flags;
|
||||
uint8_t max_adv_data_len;
|
||||
uint8_t max_scan_rsp_len;
|
||||
uint8_t max_instances;
|
||||
uint8_t num_instances;
|
||||
uint8_t instance[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_ADD_ADVERTISING 0x003E
|
||||
struct mgmt_cp_add_advertising {
|
||||
uint8_t instance;
|
||||
uint32_t flags;
|
||||
uint16_t duration;
|
||||
uint16_t timeout;
|
||||
uint8_t adv_data_len;
|
||||
uint8_t scan_rsp_len;
|
||||
uint8_t data[0];
|
||||
} __packed;
|
||||
struct mgmt_rp_add_advertising {
|
||||
uint8_t instance;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_ADV_FLAG_CONNECTABLE (1 << 0)
|
||||
#define MGMT_ADV_FLAG_DISCOV (1 << 1)
|
||||
#define MGMT_ADV_FLAG_LIMITED_DISCOV (1 << 2)
|
||||
#define MGMT_ADV_FLAG_MANAGED_FLAGS (1 << 3)
|
||||
#define MGMT_ADV_FLAG_TX_POWER (1 << 4)
|
||||
#define MGMT_ADV_FLAG_APPEARANCE (1 << 5)
|
||||
#define MGMT_ADV_FLAG_LOCAL_NAME (1 << 6)
|
||||
|
||||
#define MGMT_OP_REMOVE_ADVERTISING 0x003F
|
||||
struct mgmt_cp_remove_advertising {
|
||||
uint8_t instance;
|
||||
} __packed;
|
||||
#define MGMT_REMOVE_ADVERTISING_SIZE 1
|
||||
struct mgmt_rp_remove_advertising {
|
||||
uint8_t instance;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_GET_ADV_SIZE_INFO 0x0040
|
||||
struct mgmt_cp_get_adv_size_info {
|
||||
uint8_t instance;
|
||||
uint32_t flags;
|
||||
} __packed;
|
||||
#define MGMT_GET_ADV_SIZE_INFO_SIZE 5
|
||||
struct mgmt_rp_get_adv_size_info {
|
||||
uint8_t instance;
|
||||
uint32_t flags;
|
||||
uint8_t max_adv_data_len;
|
||||
uint8_t max_scan_rsp_len;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_START_LIMITED_DISCOVERY 0x0041
|
||||
|
||||
#define MGMT_OP_READ_EXT_INFO 0x0042
|
||||
struct mgmt_rp_read_ext_info {
|
||||
bdaddr_t bdaddr;
|
||||
uint8_t version;
|
||||
uint16_t manufacturer;
|
||||
uint32_t supported_settings;
|
||||
uint32_t current_settings;
|
||||
uint16_t eir_len;
|
||||
uint8_t eir[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_OP_SET_APPEARANCE 0x0043
|
||||
struct mgmt_cp_set_appearance {
|
||||
uint16_t appearance;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_CMD_COMPLETE 0x0001
|
||||
struct mgmt_ev_cmd_complete {
|
||||
uint16_t opcode;
|
||||
uint8_t status;
|
||||
uint8_t data[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_CMD_STATUS 0x0002
|
||||
struct mgmt_ev_cmd_status {
|
||||
uint16_t opcode;
|
||||
uint8_t status;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_CONTROLLER_ERROR 0x0003
|
||||
struct mgmt_ev_controller_error {
|
||||
uint8_t error_code;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_INDEX_ADDED 0x0004
|
||||
|
||||
#define MGMT_EV_INDEX_REMOVED 0x0005
|
||||
|
||||
#define MGMT_EV_NEW_SETTINGS 0x0006
|
||||
|
||||
#define MGMT_EV_CLASS_OF_DEV_CHANGED 0x0007
|
||||
struct mgmt_ev_class_of_dev_changed {
|
||||
uint8_t dev_class[3];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_LOCAL_NAME_CHANGED 0x0008
|
||||
struct mgmt_ev_local_name_changed {
|
||||
uint8_t name[MGMT_MAX_NAME_LENGTH];
|
||||
uint8_t short_name[MGMT_MAX_SHORT_NAME_LENGTH];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_NEW_LINK_KEY 0x0009
|
||||
struct mgmt_ev_new_link_key {
|
||||
uint8_t store_hint;
|
||||
struct mgmt_link_key_info key;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_NEW_LONG_TERM_KEY 0x000A
|
||||
struct mgmt_ev_new_long_term_key {
|
||||
uint8_t store_hint;
|
||||
struct mgmt_ltk_info key;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DEVICE_CONNECTED 0x000B
|
||||
struct mgmt_ev_device_connected {
|
||||
struct mgmt_addr_info addr;
|
||||
uint32_t flags;
|
||||
uint16_t eir_len;
|
||||
uint8_t eir[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_DEV_DISCONN_UNKNOWN 0x00
|
||||
#define MGMT_DEV_DISCONN_TIMEOUT 0x01
|
||||
#define MGMT_DEV_DISCONN_LOCAL_HOST 0x02
|
||||
#define MGMT_DEV_DISCONN_REMOTE 0x03
|
||||
|
||||
#define MGMT_EV_DEVICE_DISCONNECTED 0x000C
|
||||
struct mgmt_ev_device_disconnected {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t reason;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_CONNECT_FAILED 0x000D
|
||||
struct mgmt_ev_connect_failed {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t status;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_PIN_CODE_REQUEST 0x000E
|
||||
struct mgmt_ev_pin_code_request {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t secure;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_USER_CONFIRM_REQUEST 0x000F
|
||||
struct mgmt_ev_user_confirm_request {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t confirm_hint;
|
||||
uint32_t value;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_USER_PASSKEY_REQUEST 0x0010
|
||||
struct mgmt_ev_user_passkey_request {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_AUTH_FAILED 0x0011
|
||||
struct mgmt_ev_auth_failed {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t status;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_DEV_FOUND_CONFIRM_NAME 0x01
|
||||
#define MGMT_DEV_FOUND_LEGACY_PAIRING 0x02
|
||||
#define MGMT_DEV_FOUND_NOT_CONNECTABLE 0x04
|
||||
|
||||
#define MGMT_EV_DEVICE_FOUND 0x0012
|
||||
struct mgmt_ev_device_found {
|
||||
struct mgmt_addr_info addr;
|
||||
int8_t rssi;
|
||||
uint32_t flags;
|
||||
uint16_t eir_len;
|
||||
uint8_t eir[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DISCOVERING 0x0013
|
||||
struct mgmt_ev_discovering {
|
||||
uint8_t type;
|
||||
uint8_t discovering;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DEVICE_BLOCKED 0x0014
|
||||
struct mgmt_ev_device_blocked {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DEVICE_UNBLOCKED 0x0015
|
||||
struct mgmt_ev_device_unblocked {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DEVICE_UNPAIRED 0x0016
|
||||
struct mgmt_ev_device_unpaired {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_PASSKEY_NOTIFY 0x0017
|
||||
struct mgmt_ev_passkey_notify {
|
||||
struct mgmt_addr_info addr;
|
||||
uint32_t passkey;
|
||||
uint8_t entered;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_NEW_IRK 0x0018
|
||||
struct mgmt_ev_new_irk {
|
||||
uint8_t store_hint;
|
||||
bdaddr_t rpa;
|
||||
struct mgmt_irk_info key;
|
||||
} __packed;
|
||||
|
||||
struct mgmt_csrk_info {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t type;
|
||||
uint8_t val[16];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_NEW_CSRK 0x0019
|
||||
struct mgmt_ev_new_csrk {
|
||||
uint8_t store_hint;
|
||||
struct mgmt_csrk_info key;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DEVICE_ADDED 0x001a
|
||||
struct mgmt_ev_device_added {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t action;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_DEVICE_REMOVED 0x001b
|
||||
struct mgmt_ev_device_removed {
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_NEW_CONN_PARAM 0x001c
|
||||
struct mgmt_ev_new_conn_param {
|
||||
struct mgmt_addr_info addr;
|
||||
uint8_t store_hint;
|
||||
uint16_t min_interval;
|
||||
uint16_t max_interval;
|
||||
uint16_t latency;
|
||||
uint16_t timeout;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_UNCONF_INDEX_ADDED 0x001d
|
||||
|
||||
#define MGMT_EV_UNCONF_INDEX_REMOVED 0x001e
|
||||
|
||||
#define MGMT_EV_NEW_CONFIG_OPTIONS 0x001f
|
||||
|
||||
#define MGMT_EV_EXT_INDEX_ADDED 0x0020
|
||||
struct mgmt_ev_ext_index_added {
|
||||
uint8_t type;
|
||||
uint8_t bus;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_EXT_INDEX_REMOVED 0x0021
|
||||
struct mgmt_ev_ext_index_removed {
|
||||
uint8_t type;
|
||||
uint8_t bus;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_LOCAL_OOB_DATA_UPDATED 0x0022
|
||||
struct mgmt_ev_local_oob_data_updated {
|
||||
uint8_t type;
|
||||
uint16_t eir_len;
|
||||
uint8_t eir[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_ADVERTISING_ADDED 0x0023
|
||||
struct mgmt_ev_advertising_added {
|
||||
uint8_t instance;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_ADVERTISING_REMOVED 0x0024
|
||||
struct mgmt_ev_advertising_removed {
|
||||
uint8_t instance;
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_EXT_INFO_CHANGED 0x0025
|
||||
struct mgmt_ev_ext_info_changed {
|
||||
uint16_t eir_len;
|
||||
uint8_t eir[0];
|
||||
} __packed;
|
||||
|
||||
static const char *mgmt_op[] = {
|
||||
"<0x0000>",
|
||||
"Read Version",
|
||||
"Read Commands",
|
||||
"Read Index List",
|
||||
"Read Controller Info",
|
||||
"Set Powered",
|
||||
"Set Discoverable",
|
||||
"Set Connectable",
|
||||
"Set Fast Connectable", /* 0x0008 */
|
||||
"Set Bondable",
|
||||
"Set Link Security",
|
||||
"Set Secure Simple Pairing",
|
||||
"Set High Speed",
|
||||
"Set Low Energy",
|
||||
"Set Dev Class",
|
||||
"Set Local Name",
|
||||
"Add UUID", /* 0x0010 */
|
||||
"Remove UUID",
|
||||
"Load Link Keys",
|
||||
"Load Long Term Keys",
|
||||
"Disconnect",
|
||||
"Get Connections",
|
||||
"PIN Code Reply",
|
||||
"PIN Code Neg Reply",
|
||||
"Set IO Capability", /* 0x0018 */
|
||||
"Pair Device",
|
||||
"Cancel Pair Device",
|
||||
"Unpair Device",
|
||||
"User Confirm Reply",
|
||||
"User Confirm Neg Reply",
|
||||
"User Passkey Reply",
|
||||
"User Passkey Neg Reply",
|
||||
"Read Local OOB Data", /* 0x0020 */
|
||||
"Add Remote OOB Data",
|
||||
"Remove Remove OOB Data",
|
||||
"Start Discovery",
|
||||
"Stop Discovery",
|
||||
"Confirm Name",
|
||||
"Block Device",
|
||||
"Unblock Device",
|
||||
"Set Device ID", /* 0x0028 */
|
||||
"Set Advertising",
|
||||
"Set BR/EDR",
|
||||
"Set Static Address",
|
||||
"Set Scan Parameters",
|
||||
"Set Secure Connections",
|
||||
"Set Debug Keys",
|
||||
"Set Privacy",
|
||||
"Load Identity Resolving Keys", /* 0x0030 */
|
||||
"Get Connection Information",
|
||||
"Get Clock Information",
|
||||
"Add Device",
|
||||
"Remove Device",
|
||||
"Load Connection Parameters",
|
||||
"Read Unconfigured Index List",
|
||||
"Read Controller Configuration Information",
|
||||
"Set External Configuration", /* 0x0038 */
|
||||
"Set Public Address",
|
||||
"Start Service Discovery",
|
||||
"Read Local Out Of Band Extended Data",
|
||||
"Read Extended Controller Index List",
|
||||
"Read Advertising Features",
|
||||
"Add Advertising",
|
||||
"Remove Advertising",
|
||||
"Get Advertising Size Information", /* 0x0040 */
|
||||
"Start Limited Discovery",
|
||||
"Read Extended Controller Information",
|
||||
"Set Appearance",
|
||||
};
|
||||
|
||||
static const char *mgmt_ev[] = {
|
||||
"<0x0000>",
|
||||
"Command Complete",
|
||||
"Command Status",
|
||||
"Controller Error",
|
||||
"Index Added",
|
||||
"Index Removed",
|
||||
"New Settings",
|
||||
"Class of Device Changed",
|
||||
"Local Name Changed", /* 0x0008 */
|
||||
"New Link Key",
|
||||
"New Long Term Key",
|
||||
"Device Connected",
|
||||
"Device Disconnected",
|
||||
"Connect Failed",
|
||||
"PIN Code Request",
|
||||
"User Confirm Request",
|
||||
"User Passkey Request", /* 0x0010 */
|
||||
"Authentication Failed",
|
||||
"Device Found",
|
||||
"Discovering",
|
||||
"Device Blocked",
|
||||
"Device Unblocked",
|
||||
"Device Unpaired",
|
||||
"Passkey Notify",
|
||||
"New Identity Resolving Key", /* 0x0018 */
|
||||
"New Signature Resolving Key",
|
||||
"Device Added",
|
||||
"Device Removed",
|
||||
"New Connection Parameter",
|
||||
"Unconfigured Index Added",
|
||||
"Unconfigured Index Removed",
|
||||
"New Configuration Options",
|
||||
"Extended Index Added", /* 0x0020 */
|
||||
"Extended Index Removed",
|
||||
"Local Out Of Band Extended Data Updated",
|
||||
"Advertising Added",
|
||||
"Advertising Removed",
|
||||
"Extended Controller Information Changed",
|
||||
};
|
||||
|
||||
static const char *mgmt_status[] = {
|
||||
"Success",
|
||||
"Unknown Command",
|
||||
"Not Connected",
|
||||
"Failed",
|
||||
"Connect Failed",
|
||||
"Authentication Failed",
|
||||
"Not Paired",
|
||||
"No Resources",
|
||||
"Timeout",
|
||||
"Already Connected",
|
||||
"Busy",
|
||||
"Rejected",
|
||||
"Not Supported",
|
||||
"Invalid Parameters",
|
||||
"Disconnected",
|
||||
"Not Powered",
|
||||
"Cancelled",
|
||||
"Invalid Index",
|
||||
"Blocked through rfkill",
|
||||
"Already Paired",
|
||||
"Permission Denied",
|
||||
};
|
||||
|
||||
#ifndef NELEM
|
||||
#define NELEM(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
static inline const char *mgmt_opstr(uint16_t op)
|
||||
{
|
||||
if (op >= NELEM(mgmt_op))
|
||||
return "<unknown opcode>";
|
||||
return mgmt_op[op];
|
||||
}
|
||||
|
||||
static inline const char *mgmt_evstr(uint16_t ev)
|
||||
{
|
||||
if (ev >= NELEM(mgmt_ev))
|
||||
return "<unknown event>";
|
||||
return mgmt_ev[ev];
|
||||
}
|
||||
|
||||
static inline const char *mgmt_errstr(uint8_t status)
|
||||
{
|
||||
if (status >= NELEM(mgmt_status))
|
||||
return "<unknown status>";
|
||||
return mgmt_status[status];
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __RFCOMM_H
|
||||
#define __RFCOMM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
/* RFCOMM defaults */
|
||||
#define RFCOMM_DEFAULT_MTU 127
|
||||
|
||||
#define RFCOMM_PSM 3
|
||||
|
||||
/* RFCOMM socket address */
|
||||
struct sockaddr_rc {
|
||||
sa_family_t rc_family;
|
||||
bdaddr_t rc_bdaddr;
|
||||
uint8_t rc_channel;
|
||||
};
|
||||
|
||||
/* RFCOMM socket options */
|
||||
#define RFCOMM_CONNINFO 0x02
|
||||
struct rfcomm_conninfo {
|
||||
uint16_t hci_handle;
|
||||
uint8_t dev_class[3];
|
||||
};
|
||||
|
||||
#define RFCOMM_LM 0x03
|
||||
#define RFCOMM_LM_MASTER 0x0001
|
||||
#define RFCOMM_LM_AUTH 0x0002
|
||||
#define RFCOMM_LM_ENCRYPT 0x0004
|
||||
#define RFCOMM_LM_TRUSTED 0x0008
|
||||
#define RFCOMM_LM_RELIABLE 0x0010
|
||||
#define RFCOMM_LM_SECURE 0x0020
|
||||
|
||||
/* RFCOMM TTY support */
|
||||
#define RFCOMM_MAX_DEV 256
|
||||
|
||||
#define RFCOMMCREATEDEV _IOW('R', 200, int)
|
||||
#define RFCOMMRELEASEDEV _IOW('R', 201, int)
|
||||
#define RFCOMMGETDEVLIST _IOR('R', 210, int)
|
||||
#define RFCOMMGETDEVINFO _IOR('R', 211, int)
|
||||
|
||||
struct rfcomm_dev_req {
|
||||
int16_t dev_id;
|
||||
uint32_t flags;
|
||||
bdaddr_t src;
|
||||
bdaddr_t dst;
|
||||
uint8_t channel;
|
||||
};
|
||||
#define RFCOMM_REUSE_DLC 0
|
||||
#define RFCOMM_RELEASE_ONHUP 1
|
||||
#define RFCOMM_HANGUP_NOW 2
|
||||
#define RFCOMM_TTY_ATTACHED 3
|
||||
|
||||
struct rfcomm_dev_info {
|
||||
int16_t id;
|
||||
uint32_t flags;
|
||||
uint16_t state;
|
||||
bdaddr_t src;
|
||||
bdaddr_t dst;
|
||||
uint8_t channel;
|
||||
};
|
||||
|
||||
struct rfcomm_dev_list_req {
|
||||
uint16_t dev_num;
|
||||
struct rfcomm_dev_info dev_info[0];
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __RFCOMM_H */
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SCO_H
|
||||
#define __SCO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* SCO defaults */
|
||||
#define SCO_DEFAULT_MTU 500
|
||||
#define SCO_DEFAULT_FLUSH_TO 0xFFFF
|
||||
|
||||
#define SCO_CONN_TIMEOUT (HZ * 40)
|
||||
#define SCO_DISCONN_TIMEOUT (HZ * 2)
|
||||
#define SCO_CONN_IDLE_TIMEOUT (HZ * 60)
|
||||
|
||||
/* SCO socket address */
|
||||
struct sockaddr_sco {
|
||||
sa_family_t sco_family;
|
||||
bdaddr_t sco_bdaddr;
|
||||
};
|
||||
|
||||
/* set/get sockopt defines */
|
||||
#define SCO_OPTIONS 0x01
|
||||
struct sco_options {
|
||||
uint16_t mtu;
|
||||
};
|
||||
|
||||
#define SCO_CONNINFO 0x02
|
||||
struct sco_conninfo {
|
||||
uint16_t hci_handle;
|
||||
uint8_t dev_class[3];
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SCO_H */
|
|
@ -1,542 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2001-2002 Nokia Corporation
|
||||
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
* Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SDP_H
|
||||
#define __SDP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include "bluetooth.h"
|
||||
|
||||
#define SDP_UNIX_PATH "/var/run/sdp"
|
||||
#define SDP_RESPONSE_TIMEOUT 20
|
||||
#define SDP_REQ_BUFFER_SIZE 2048
|
||||
#define SDP_RSP_BUFFER_SIZE 65535
|
||||
#define SDP_PDU_CHUNK_SIZE 1024
|
||||
|
||||
/*
|
||||
* All definitions are based on Bluetooth Assigned Numbers
|
||||
* of the Bluetooth Specification
|
||||
*/
|
||||
#define SDP_PSM 0x0001
|
||||
|
||||
/*
|
||||
* Protocol UUIDs
|
||||
*/
|
||||
#define SDP_UUID 0x0001
|
||||
#define UDP_UUID 0x0002
|
||||
#define RFCOMM_UUID 0x0003
|
||||
#define TCP_UUID 0x0004
|
||||
#define TCS_BIN_UUID 0x0005
|
||||
#define TCS_AT_UUID 0x0006
|
||||
#define ATT_UUID 0x0007
|
||||
#define OBEX_UUID 0x0008
|
||||
#define IP_UUID 0x0009
|
||||
#define FTP_UUID 0x000a
|
||||
#define HTTP_UUID 0x000c
|
||||
#define WSP_UUID 0x000e
|
||||
#define BNEP_UUID 0x000f
|
||||
#define UPNP_UUID 0x0010
|
||||
#define HIDP_UUID 0x0011
|
||||
#define HCRP_CTRL_UUID 0x0012
|
||||
#define HCRP_DATA_UUID 0x0014
|
||||
#define HCRP_NOTE_UUID 0x0016
|
||||
#define AVCTP_UUID 0x0017
|
||||
#define AVDTP_UUID 0x0019
|
||||
#define CMTP_UUID 0x001b
|
||||
#define UDI_UUID 0x001d
|
||||
#define MCAP_CTRL_UUID 0x001e
|
||||
#define MCAP_DATA_UUID 0x001f
|
||||
#define L2CAP_UUID 0x0100
|
||||
|
||||
/*
|
||||
* Service class identifiers of standard services and service groups
|
||||
*/
|
||||
#define SDP_SERVER_SVCLASS_ID 0x1000
|
||||
#define BROWSE_GRP_DESC_SVCLASS_ID 0x1001
|
||||
#define PUBLIC_BROWSE_GROUP 0x1002
|
||||
#define SERIAL_PORT_SVCLASS_ID 0x1101
|
||||
#define LAN_ACCESS_SVCLASS_ID 0x1102
|
||||
#define DIALUP_NET_SVCLASS_ID 0x1103
|
||||
#define IRMC_SYNC_SVCLASS_ID 0x1104
|
||||
#define OBEX_OBJPUSH_SVCLASS_ID 0x1105
|
||||
#define OBEX_FILETRANS_SVCLASS_ID 0x1106
|
||||
#define IRMC_SYNC_CMD_SVCLASS_ID 0x1107
|
||||
#define HEADSET_SVCLASS_ID 0x1108
|
||||
#define CORDLESS_TELEPHONY_SVCLASS_ID 0x1109
|
||||
#define AUDIO_SOURCE_SVCLASS_ID 0x110a
|
||||
#define AUDIO_SINK_SVCLASS_ID 0x110b
|
||||
#define AV_REMOTE_TARGET_SVCLASS_ID 0x110c
|
||||
#define ADVANCED_AUDIO_SVCLASS_ID 0x110d
|
||||
#define AV_REMOTE_SVCLASS_ID 0x110e
|
||||
#define AV_REMOTE_CONTROLLER_SVCLASS_ID 0x110f
|
||||
#define INTERCOM_SVCLASS_ID 0x1110
|
||||
#define FAX_SVCLASS_ID 0x1111
|
||||
#define HEADSET_AGW_SVCLASS_ID 0x1112
|
||||
#define WAP_SVCLASS_ID 0x1113
|
||||
#define WAP_CLIENT_SVCLASS_ID 0x1114
|
||||
#define PANU_SVCLASS_ID 0x1115
|
||||
#define NAP_SVCLASS_ID 0x1116
|
||||
#define GN_SVCLASS_ID 0x1117
|
||||
#define DIRECT_PRINTING_SVCLASS_ID 0x1118
|
||||
#define REFERENCE_PRINTING_SVCLASS_ID 0x1119
|
||||
#define IMAGING_SVCLASS_ID 0x111a
|
||||
#define IMAGING_RESPONDER_SVCLASS_ID 0x111b
|
||||
#define IMAGING_ARCHIVE_SVCLASS_ID 0x111c
|
||||
#define IMAGING_REFOBJS_SVCLASS_ID 0x111d
|
||||
#define HANDSFREE_SVCLASS_ID 0x111e
|
||||
#define HANDSFREE_AGW_SVCLASS_ID 0x111f
|
||||
#define DIRECT_PRT_REFOBJS_SVCLASS_ID 0x1120
|
||||
#define REFLECTED_UI_SVCLASS_ID 0x1121
|
||||
#define BASIC_PRINTING_SVCLASS_ID 0x1122
|
||||
#define PRINTING_STATUS_SVCLASS_ID 0x1123
|
||||
#define HID_SVCLASS_ID 0x1124
|
||||
#define HCR_SVCLASS_ID 0x1125
|
||||
#define HCR_PRINT_SVCLASS_ID 0x1126
|
||||
#define HCR_SCAN_SVCLASS_ID 0x1127
|
||||
#define CIP_SVCLASS_ID 0x1128
|
||||
#define VIDEO_CONF_GW_SVCLASS_ID 0x1129
|
||||
#define UDI_MT_SVCLASS_ID 0x112a
|
||||
#define UDI_TA_SVCLASS_ID 0x112b
|
||||
#define AV_SVCLASS_ID 0x112c
|
||||
#define SAP_SVCLASS_ID 0x112d
|
||||
#define PBAP_PCE_SVCLASS_ID 0x112e
|
||||
#define PBAP_PSE_SVCLASS_ID 0x112f
|
||||
#define PBAP_SVCLASS_ID 0x1130
|
||||
#define MAP_MSE_SVCLASS_ID 0x1132
|
||||
#define MAP_MCE_SVCLASS_ID 0x1133
|
||||
#define MAP_SVCLASS_ID 0x1134
|
||||
#define GNSS_SVCLASS_ID 0x1135
|
||||
#define GNSS_SERVER_SVCLASS_ID 0x1136
|
||||
#define MPS_SC_SVCLASS_ID 0x113A
|
||||
#define MPS_SVCLASS_ID 0x113B
|
||||
#define PNP_INFO_SVCLASS_ID 0x1200
|
||||
#define GENERIC_NETWORKING_SVCLASS_ID 0x1201
|
||||
#define GENERIC_FILETRANS_SVCLASS_ID 0x1202
|
||||
#define GENERIC_AUDIO_SVCLASS_ID 0x1203
|
||||
#define GENERIC_TELEPHONY_SVCLASS_ID 0x1204
|
||||
#define UPNP_SVCLASS_ID 0x1205
|
||||
#define UPNP_IP_SVCLASS_ID 0x1206
|
||||
#define UPNP_PAN_SVCLASS_ID 0x1300
|
||||
#define UPNP_LAP_SVCLASS_ID 0x1301
|
||||
#define UPNP_L2CAP_SVCLASS_ID 0x1302
|
||||
#define VIDEO_SOURCE_SVCLASS_ID 0x1303
|
||||
#define VIDEO_SINK_SVCLASS_ID 0x1304
|
||||
#define VIDEO_DISTRIBUTION_SVCLASS_ID 0x1305
|
||||
#define HDP_SVCLASS_ID 0x1400
|
||||
#define HDP_SOURCE_SVCLASS_ID 0x1401
|
||||
#define HDP_SINK_SVCLASS_ID 0x1402
|
||||
#define GENERIC_ACCESS_SVCLASS_ID 0x1800
|
||||
#define GENERIC_ATTRIB_SVCLASS_ID 0x1801
|
||||
#define APPLE_AGENT_SVCLASS_ID 0x2112
|
||||
|
||||
/*
|
||||
* Standard profile descriptor identifiers; note these
|
||||
* may be identical to some of the service classes defined above
|
||||
*/
|
||||
#define SDP_SERVER_PROFILE_ID SDP_SERVER_SVCLASS_ID
|
||||
#define BROWSE_GRP_DESC_PROFILE_ID BROWSE_GRP_DESC_SVCLASS_ID
|
||||
#define SERIAL_PORT_PROFILE_ID SERIAL_PORT_SVCLASS_ID
|
||||
#define LAN_ACCESS_PROFILE_ID LAN_ACCESS_SVCLASS_ID
|
||||
#define DIALUP_NET_PROFILE_ID DIALUP_NET_SVCLASS_ID
|
||||
#define IRMC_SYNC_PROFILE_ID IRMC_SYNC_SVCLASS_ID
|
||||
#define OBEX_OBJPUSH_PROFILE_ID OBEX_OBJPUSH_SVCLASS_ID
|
||||
#define OBEX_FILETRANS_PROFILE_ID OBEX_FILETRANS_SVCLASS_ID
|
||||
#define IRMC_SYNC_CMD_PROFILE_ID IRMC_SYNC_CMD_SVCLASS_ID
|
||||
#define HEADSET_PROFILE_ID HEADSET_SVCLASS_ID
|
||||
#define CORDLESS_TELEPHONY_PROFILE_ID CORDLESS_TELEPHONY_SVCLASS_ID
|
||||
#define AUDIO_SOURCE_PROFILE_ID AUDIO_SOURCE_SVCLASS_ID
|
||||
#define AUDIO_SINK_PROFILE_ID AUDIO_SINK_SVCLASS_ID
|
||||
#define AV_REMOTE_TARGET_PROFILE_ID AV_REMOTE_TARGET_SVCLASS_ID
|
||||
#define ADVANCED_AUDIO_PROFILE_ID ADVANCED_AUDIO_SVCLASS_ID
|
||||
#define AV_REMOTE_PROFILE_ID AV_REMOTE_SVCLASS_ID
|
||||
#define INTERCOM_PROFILE_ID INTERCOM_SVCLASS_ID
|
||||
#define FAX_PROFILE_ID FAX_SVCLASS_ID
|
||||
#define HEADSET_AGW_PROFILE_ID HEADSET_AGW_SVCLASS_ID
|
||||
#define WAP_PROFILE_ID WAP_SVCLASS_ID
|
||||
#define WAP_CLIENT_PROFILE_ID WAP_CLIENT_SVCLASS_ID
|
||||
#define PANU_PROFILE_ID PANU_SVCLASS_ID
|
||||
#define NAP_PROFILE_ID NAP_SVCLASS_ID
|
||||
#define GN_PROFILE_ID GN_SVCLASS_ID
|
||||
#define DIRECT_PRINTING_PROFILE_ID DIRECT_PRINTING_SVCLASS_ID
|
||||
#define REFERENCE_PRINTING_PROFILE_ID REFERENCE_PRINTING_SVCLASS_ID
|
||||
#define IMAGING_PROFILE_ID IMAGING_SVCLASS_ID
|
||||
#define IMAGING_RESPONDER_PROFILE_ID IMAGING_RESPONDER_SVCLASS_ID
|
||||
#define IMAGING_ARCHIVE_PROFILE_ID IMAGING_ARCHIVE_SVCLASS_ID
|
||||
#define IMAGING_REFOBJS_PROFILE_ID IMAGING_REFOBJS_SVCLASS_ID
|
||||
#define HANDSFREE_PROFILE_ID HANDSFREE_SVCLASS_ID
|
||||
#define HANDSFREE_AGW_PROFILE_ID HANDSFREE_AGW_SVCLASS_ID
|
||||
#define DIRECT_PRT_REFOBJS_PROFILE_ID DIRECT_PRT_REFOBJS_SVCLASS_ID
|
||||
#define REFLECTED_UI_PROFILE_ID REFLECTED_UI_SVCLASS_ID
|
||||
#define BASIC_PRINTING_PROFILE_ID BASIC_PRINTING_SVCLASS_ID
|
||||
#define PRINTING_STATUS_PROFILE_ID PRINTING_STATUS_SVCLASS_ID
|
||||
#define HID_PROFILE_ID HID_SVCLASS_ID
|
||||
#define HCR_PROFILE_ID HCR_SCAN_SVCLASS_ID
|
||||
#define HCR_PRINT_PROFILE_ID HCR_PRINT_SVCLASS_ID
|
||||
#define HCR_SCAN_PROFILE_ID HCR_SCAN_SVCLASS_ID
|
||||
#define CIP_PROFILE_ID CIP_SVCLASS_ID
|
||||
#define VIDEO_CONF_GW_PROFILE_ID VIDEO_CONF_GW_SVCLASS_ID
|
||||
#define UDI_MT_PROFILE_ID UDI_MT_SVCLASS_ID
|
||||
#define UDI_TA_PROFILE_ID UDI_TA_SVCLASS_ID
|
||||
#define AV_PROFILE_ID AV_SVCLASS_ID
|
||||
#define SAP_PROFILE_ID SAP_SVCLASS_ID
|
||||
#define PBAP_PCE_PROFILE_ID PBAP_PCE_SVCLASS_ID
|
||||
#define PBAP_PSE_PROFILE_ID PBAP_PSE_SVCLASS_ID
|
||||
#define PBAP_PROFILE_ID PBAP_SVCLASS_ID
|
||||
#define MAP_PROFILE_ID MAP_SVCLASS_ID
|
||||
#define PNP_INFO_PROFILE_ID PNP_INFO_SVCLASS_ID
|
||||
#define GENERIC_NETWORKING_PROFILE_ID GENERIC_NETWORKING_SVCLASS_ID
|
||||
#define GENERIC_FILETRANS_PROFILE_ID GENERIC_FILETRANS_SVCLASS_ID
|
||||
#define GENERIC_AUDIO_PROFILE_ID GENERIC_AUDIO_SVCLASS_ID
|
||||
#define GENERIC_TELEPHONY_PROFILE_ID GENERIC_TELEPHONY_SVCLASS_ID
|
||||
#define UPNP_PROFILE_ID UPNP_SVCLASS_ID
|
||||
#define UPNP_IP_PROFILE_ID UPNP_IP_SVCLASS_ID
|
||||
#define UPNP_PAN_PROFILE_ID UPNP_PAN_SVCLASS_ID
|
||||
#define UPNP_LAP_PROFILE_ID UPNP_LAP_SVCLASS_ID
|
||||
#define UPNP_L2CAP_PROFILE_ID UPNP_L2CAP_SVCLASS_ID
|
||||
#define VIDEO_SOURCE_PROFILE_ID VIDEO_SOURCE_SVCLASS_ID
|
||||
#define VIDEO_SINK_PROFILE_ID VIDEO_SINK_SVCLASS_ID
|
||||
#define VIDEO_DISTRIBUTION_PROFILE_ID VIDEO_DISTRIBUTION_SVCLASS_ID
|
||||
#define HDP_PROFILE_ID HDP_SVCLASS_ID
|
||||
#define HDP_SOURCE_PROFILE_ID HDP_SOURCE_SVCLASS_ID
|
||||
#define HDP_SINK_PROFILE_ID HDP_SINK_SVCLASS_ID
|
||||
#define GENERIC_ACCESS_PROFILE_ID GENERIC_ACCESS_SVCLASS_ID
|
||||
#define GENERIC_ATTRIB_PROFILE_ID GENERIC_ATTRIB_SVCLASS_ID
|
||||
#define APPLE_AGENT_PROFILE_ID APPLE_AGENT_SVCLASS_ID
|
||||
#define MPS_PROFILE_ID MPS_SC_SVCLASS_ID
|
||||
|
||||
/*
|
||||
* Compatibility macros for the old MDP acronym
|
||||
*/
|
||||
#define MDP_SVCLASS_ID HDP_SVCLASS_ID
|
||||
#define MDP_SOURCE_SVCLASS_ID HDP_SOURCE_SVCLASS_ID
|
||||
#define MDP_SINK_SVCLASS_ID HDP_SINK_SVCLASS_ID
|
||||
#define MDP_PROFILE_ID HDP_PROFILE_ID
|
||||
#define MDP_SOURCE_PROFILE_ID HDP_SOURCE_PROFILE_ID
|
||||
#define MDP_SINK_PROFILE_ID HDP_SINK_PROFILE_ID
|
||||
|
||||
/*
|
||||
* Attribute identifier codes
|
||||
*/
|
||||
#define SDP_SERVER_RECORD_HANDLE 0x0000
|
||||
|
||||
/*
|
||||
* Possible values for attribute-id are listed below.
|
||||
* See SDP Spec, section "Service Attribute Definitions" for more details.
|
||||
*/
|
||||
#define SDP_ATTR_RECORD_HANDLE 0x0000
|
||||
#define SDP_ATTR_SVCLASS_ID_LIST 0x0001
|
||||
#define SDP_ATTR_RECORD_STATE 0x0002
|
||||
#define SDP_ATTR_SERVICE_ID 0x0003
|
||||
#define SDP_ATTR_PROTO_DESC_LIST 0x0004
|
||||
#define SDP_ATTR_BROWSE_GRP_LIST 0x0005
|
||||
#define SDP_ATTR_LANG_BASE_ATTR_ID_LIST 0x0006
|
||||
#define SDP_ATTR_SVCINFO_TTL 0x0007
|
||||
#define SDP_ATTR_SERVICE_AVAILABILITY 0x0008
|
||||
#define SDP_ATTR_PFILE_DESC_LIST 0x0009
|
||||
#define SDP_ATTR_DOC_URL 0x000a
|
||||
#define SDP_ATTR_CLNT_EXEC_URL 0x000b
|
||||
#define SDP_ATTR_ICON_URL 0x000c
|
||||
#define SDP_ATTR_ADD_PROTO_DESC_LIST 0x000d
|
||||
|
||||
#define SDP_ATTR_GROUP_ID 0x0200
|
||||
#define SDP_ATTR_IP_SUBNET 0x0200
|
||||
#define SDP_ATTR_VERSION_NUM_LIST 0x0200
|
||||
#define SDP_ATTR_SUPPORTED_FEATURES_LIST 0x0200
|
||||
#define SDP_ATTR_GOEP_L2CAP_PSM 0x0200
|
||||
#define SDP_ATTR_SVCDB_STATE 0x0201
|
||||
|
||||
#define SDP_ATTR_MPSD_SCENARIOS 0x0200
|
||||
#define SDP_ATTR_MPMD_SCENARIOS 0x0201
|
||||
#define SDP_ATTR_MPS_DEPENDENCIES 0x0202
|
||||
|
||||
#define SDP_ATTR_SERVICE_VERSION 0x0300
|
||||
#define SDP_ATTR_EXTERNAL_NETWORK 0x0301
|
||||
#define SDP_ATTR_SUPPORTED_DATA_STORES_LIST 0x0301
|
||||
#define SDP_ATTR_DATA_EXCHANGE_SPEC 0x0301
|
||||
#define SDP_ATTR_NETWORK 0x0301
|
||||
#define SDP_ATTR_FAX_CLASS1_SUPPORT 0x0302
|
||||
#define SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL 0x0302
|
||||
#define SDP_ATTR_MCAP_SUPPORTED_PROCEDURES 0x0302
|
||||
#define SDP_ATTR_FAX_CLASS20_SUPPORT 0x0303
|
||||
#define SDP_ATTR_SUPPORTED_FORMATS_LIST 0x0303
|
||||
#define SDP_ATTR_FAX_CLASS2_SUPPORT 0x0304
|
||||
#define SDP_ATTR_AUDIO_FEEDBACK_SUPPORT 0x0305
|
||||
#define SDP_ATTR_NETWORK_ADDRESS 0x0306
|
||||
#define SDP_ATTR_WAP_GATEWAY 0x0307
|
||||
#define SDP_ATTR_HOMEPAGE_URL 0x0308
|
||||
#define SDP_ATTR_WAP_STACK_TYPE 0x0309
|
||||
#define SDP_ATTR_SECURITY_DESC 0x030a
|
||||
#define SDP_ATTR_NET_ACCESS_TYPE 0x030b
|
||||
#define SDP_ATTR_MAX_NET_ACCESSRATE 0x030c
|
||||
#define SDP_ATTR_IP4_SUBNET 0x030d
|
||||
#define SDP_ATTR_IP6_SUBNET 0x030e
|
||||
#define SDP_ATTR_SUPPORTED_CAPABILITIES 0x0310
|
||||
#define SDP_ATTR_SUPPORTED_FEATURES 0x0311
|
||||
#define SDP_ATTR_SUPPORTED_FUNCTIONS 0x0312
|
||||
#define SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY 0x0313
|
||||
#define SDP_ATTR_SUPPORTED_REPOSITORIES 0x0314
|
||||
#define SDP_ATTR_MAS_INSTANCE_ID 0x0315
|
||||
#define SDP_ATTR_SUPPORTED_MESSAGE_TYPES 0x0316
|
||||
#define SDP_ATTR_PBAP_SUPPORTED_FEATURES 0x0317
|
||||
#define SDP_ATTR_MAP_SUPPORTED_FEATURES 0x0317
|
||||
|
||||
#define SDP_ATTR_SPECIFICATION_ID 0x0200
|
||||
#define SDP_ATTR_VENDOR_ID 0x0201
|
||||
#define SDP_ATTR_PRODUCT_ID 0x0202
|
||||
#define SDP_ATTR_VERSION 0x0203
|
||||
#define SDP_ATTR_PRIMARY_RECORD 0x0204
|
||||
#define SDP_ATTR_VENDOR_ID_SOURCE 0x0205
|
||||
|
||||
#define SDP_ATTR_HID_DEVICE_RELEASE_NUMBER 0x0200
|
||||
#define SDP_ATTR_HID_PARSER_VERSION 0x0201
|
||||
#define SDP_ATTR_HID_DEVICE_SUBCLASS 0x0202
|
||||
#define SDP_ATTR_HID_COUNTRY_CODE 0x0203
|
||||
#define SDP_ATTR_HID_VIRTUAL_CABLE 0x0204
|
||||
#define SDP_ATTR_HID_RECONNECT_INITIATE 0x0205
|
||||
#define SDP_ATTR_HID_DESCRIPTOR_LIST 0x0206
|
||||
#define SDP_ATTR_HID_LANG_ID_BASE_LIST 0x0207
|
||||
#define SDP_ATTR_HID_SDP_DISABLE 0x0208
|
||||
#define SDP_ATTR_HID_BATTERY_POWER 0x0209
|
||||
#define SDP_ATTR_HID_REMOTE_WAKEUP 0x020a
|
||||
#define SDP_ATTR_HID_PROFILE_VERSION 0x020b
|
||||
#define SDP_ATTR_HID_SUPERVISION_TIMEOUT 0x020c
|
||||
#define SDP_ATTR_HID_NORMALLY_CONNECTABLE 0x020d
|
||||
#define SDP_ATTR_HID_BOOT_DEVICE 0x020e
|
||||
|
||||
/*
|
||||
* These identifiers are based on the SDP spec stating that
|
||||
* "base attribute id of the primary (universal) language must be 0x0100"
|
||||
*
|
||||
* Other languages should have their own offset; e.g.:
|
||||
* #define XXXLangBase yyyy
|
||||
* #define AttrServiceName_XXX 0x0000+XXXLangBase
|
||||
*/
|
||||
#define SDP_PRIMARY_LANG_BASE 0x0100
|
||||
|
||||
#define SDP_ATTR_SVCNAME_PRIMARY 0x0000 + SDP_PRIMARY_LANG_BASE
|
||||
#define SDP_ATTR_SVCDESC_PRIMARY 0x0001 + SDP_PRIMARY_LANG_BASE
|
||||
#define SDP_ATTR_PROVNAME_PRIMARY 0x0002 + SDP_PRIMARY_LANG_BASE
|
||||
|
||||
/*
|
||||
* The Data representation in SDP PDUs (pps 339, 340 of BT SDP Spec)
|
||||
* These are the exact data type+size descriptor values
|
||||
* that go into the PDU buffer.
|
||||
*
|
||||
* The datatype (leading 5bits) + size descriptor (last 3 bits)
|
||||
* is 8 bits. The size descriptor is critical to extract the
|
||||
* right number of bytes for the data value from the PDU.
|
||||
*
|
||||
* For most basic types, the datatype+size descriptor is
|
||||
* straightforward. However for constructed types and strings,
|
||||
* the size of the data is in the next "n" bytes following the
|
||||
* 8 bits (datatype+size) descriptor. Exactly what the "n" is
|
||||
* specified in the 3 bits of the data size descriptor.
|
||||
*
|
||||
* TextString and URLString can be of size 2^{8, 16, 32} bytes
|
||||
* DataSequence and DataSequenceAlternates can be of size 2^{8, 16, 32}
|
||||
* The size are computed post-facto in the API and are not known apriori
|
||||
*/
|
||||
#define SDP_DATA_NIL 0x00
|
||||
#define SDP_UINT8 0x08
|
||||
#define SDP_UINT16 0x09
|
||||
#define SDP_UINT32 0x0A
|
||||
#define SDP_UINT64 0x0B
|
||||
#define SDP_UINT128 0x0C
|
||||
#define SDP_INT8 0x10
|
||||
#define SDP_INT16 0x11
|
||||
#define SDP_INT32 0x12
|
||||
#define SDP_INT64 0x13
|
||||
#define SDP_INT128 0x14
|
||||
#define SDP_UUID_UNSPEC 0x18
|
||||
#define SDP_UUID16 0x19
|
||||
#define SDP_UUID32 0x1A
|
||||
#define SDP_UUID128 0x1C
|
||||
#define SDP_TEXT_STR_UNSPEC 0x20
|
||||
#define SDP_TEXT_STR8 0x25
|
||||
#define SDP_TEXT_STR16 0x26
|
||||
#define SDP_TEXT_STR32 0x27
|
||||
#define SDP_BOOL 0x28
|
||||
#define SDP_SEQ_UNSPEC 0x30
|
||||
#define SDP_SEQ8 0x35
|
||||
#define SDP_SEQ16 0x36
|
||||
#define SDP_SEQ32 0x37
|
||||
#define SDP_ALT_UNSPEC 0x38
|
||||
#define SDP_ALT8 0x3D
|
||||
#define SDP_ALT16 0x3E
|
||||
#define SDP_ALT32 0x3F
|
||||
#define SDP_URL_STR_UNSPEC 0x40
|
||||
#define SDP_URL_STR8 0x45
|
||||
#define SDP_URL_STR16 0x46
|
||||
#define SDP_URL_STR32 0x47
|
||||
|
||||
/*
|
||||
* The PDU identifiers of SDP packets between client and server
|
||||
*/
|
||||
#define SDP_ERROR_RSP 0x01
|
||||
#define SDP_SVC_SEARCH_REQ 0x02
|
||||
#define SDP_SVC_SEARCH_RSP 0x03
|
||||
#define SDP_SVC_ATTR_REQ 0x04
|
||||
#define SDP_SVC_ATTR_RSP 0x05
|
||||
#define SDP_SVC_SEARCH_ATTR_REQ 0x06
|
||||
#define SDP_SVC_SEARCH_ATTR_RSP 0x07
|
||||
|
||||
/*
|
||||
* Some additions to support service registration.
|
||||
* These are outside the scope of the Bluetooth specification
|
||||
*/
|
||||
#define SDP_SVC_REGISTER_REQ 0x75
|
||||
#define SDP_SVC_REGISTER_RSP 0x76
|
||||
#define SDP_SVC_UPDATE_REQ 0x77
|
||||
#define SDP_SVC_UPDATE_RSP 0x78
|
||||
#define SDP_SVC_REMOVE_REQ 0x79
|
||||
#define SDP_SVC_REMOVE_RSP 0x80
|
||||
|
||||
/*
|
||||
* SDP Error codes
|
||||
*/
|
||||
#define SDP_INVALID_VERSION 0x0001
|
||||
#define SDP_INVALID_RECORD_HANDLE 0x0002
|
||||
#define SDP_INVALID_SYNTAX 0x0003
|
||||
#define SDP_INVALID_PDU_SIZE 0x0004
|
||||
#define SDP_INVALID_CSTATE 0x0005
|
||||
|
||||
/*
|
||||
* SDP PDU
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t pdu_id;
|
||||
uint16_t tid;
|
||||
uint16_t plen;
|
||||
} __attribute__ ((packed)) sdp_pdu_hdr_t;
|
||||
|
||||
/*
|
||||
* Common definitions for attributes in the SDP.
|
||||
* Should the type of any of these change, you need only make a change here.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
union {
|
||||
uint16_t uuid16;
|
||||
uint32_t uuid32;
|
||||
uint128_t uuid128;
|
||||
} value;
|
||||
} uuid_t;
|
||||
|
||||
#define SDP_IS_UUID(x) ((x) == SDP_UUID16 || (x) == SDP_UUID32 || \
|
||||
(x) == SDP_UUID128)
|
||||
#define SDP_IS_ALT(x) ((x) == SDP_ALT8 || (x) == SDP_ALT16 || (x) == SDP_ALT32)
|
||||
#define SDP_IS_SEQ(x) ((x) == SDP_SEQ8 || (x) == SDP_SEQ16 || (x) == SDP_SEQ32)
|
||||
#define SDP_IS_TEXT_STR(x) ((x) == SDP_TEXT_STR8 || (x) == SDP_TEXT_STR16 || \
|
||||
(x) == SDP_TEXT_STR32)
|
||||
|
||||
typedef struct _sdp_list sdp_list_t;
|
||||
struct _sdp_list {
|
||||
sdp_list_t *next;
|
||||
void *data;
|
||||
};
|
||||
|
||||
/*
|
||||
* User-visible strings can be in many languages
|
||||
* in addition to the universal language.
|
||||
*
|
||||
* Language meta-data includes language code in ISO639
|
||||
* followed by the encoding format. The third field in this
|
||||
* structure is the attribute offset for the language.
|
||||
* User-visible strings in the specified language can be
|
||||
* obtained at this offset.
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t code_ISO639;
|
||||
uint16_t encoding;
|
||||
uint16_t base_offset;
|
||||
} sdp_lang_attr_t;
|
||||
|
||||
/*
|
||||
* Profile descriptor is the Bluetooth profile metadata. If a
|
||||
* service conforms to a well-known profile, then its profile
|
||||
* identifier (UUID) is an attribute of the service. In addition,
|
||||
* if the profile has a version number it is specified here.
|
||||
*/
|
||||
typedef struct {
|
||||
uuid_t uuid;
|
||||
uint16_t version;
|
||||
} sdp_profile_desc_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t major;
|
||||
uint8_t minor;
|
||||
} sdp_version_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *data;
|
||||
uint32_t data_size;
|
||||
uint32_t buf_size;
|
||||
} sdp_buf_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t handle;
|
||||
|
||||
/* Search pattern: a sequence of all UUIDs seen in this record */
|
||||
sdp_list_t *pattern;
|
||||
sdp_list_t *attrlist;
|
||||
|
||||
/* Main service class for Extended Inquiry Response */
|
||||
uuid_t svclass;
|
||||
} sdp_record_t;
|
||||
|
||||
typedef struct sdp_data_struct sdp_data_t;
|
||||
struct sdp_data_struct {
|
||||
uint8_t dtd;
|
||||
uint16_t attrId;
|
||||
union {
|
||||
int8_t int8;
|
||||
int16_t int16;
|
||||
int32_t int32;
|
||||
int64_t int64;
|
||||
uint128_t int128;
|
||||
uint8_t uint8;
|
||||
uint16_t uint16;
|
||||
uint32_t uint32;
|
||||
uint64_t uint64;
|
||||
uint128_t uint128;
|
||||
uuid_t uuid;
|
||||
char *str;
|
||||
sdp_data_t *dataseq;
|
||||
} val;
|
||||
sdp_data_t *next;
|
||||
int unitSize;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SDP_H */
|
|
@ -1,634 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2001-2002 Nokia Corporation
|
||||
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
|
||||
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
||||
* Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SDP_LIB_H
|
||||
#define __SDP_LIB_H
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include "bluetooth.h"
|
||||
#include "hci.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* SDP lists
|
||||
*/
|
||||
typedef void(*sdp_list_func_t)(void *, void *);
|
||||
typedef void(*sdp_free_func_t)(void *);
|
||||
typedef int (*sdp_comp_func_t)(const void *, const void *);
|
||||
|
||||
sdp_list_t *sdp_list_append(sdp_list_t *list, void *d);
|
||||
sdp_list_t *sdp_list_remove(sdp_list_t *list, void *d);
|
||||
sdp_list_t *sdp_list_insert_sorted(sdp_list_t *list, void *data, sdp_comp_func_t f);
|
||||
void sdp_list_free(sdp_list_t *list, sdp_free_func_t f);
|
||||
|
||||
static inline int sdp_list_len(const sdp_list_t *list)
|
||||
{
|
||||
int n = 0;
|
||||
for (; list; list = list->next)
|
||||
n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
static inline sdp_list_t *sdp_list_find(sdp_list_t *list, void *u, sdp_comp_func_t f)
|
||||
{
|
||||
for (; list; list = list->next)
|
||||
if (f(list->data, u) == 0)
|
||||
return list;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void sdp_list_foreach(sdp_list_t *list, sdp_list_func_t f, void *u)
|
||||
{
|
||||
for (; list; list = list->next)
|
||||
f(list->data, u);
|
||||
}
|
||||
|
||||
/*
|
||||
* Values of the flags parameter to sdp_record_register
|
||||
*/
|
||||
#define SDP_RECORD_PERSIST 0x01
|
||||
#define SDP_DEVICE_RECORD 0x02
|
||||
|
||||
/*
|
||||
* Values of the flags parameter to sdp_connect
|
||||
*/
|
||||
#define SDP_RETRY_IF_BUSY 0x01
|
||||
#define SDP_WAIT_ON_CLOSE 0x02
|
||||
#define SDP_NON_BLOCKING 0x04
|
||||
#define SDP_LARGE_MTU 0x08
|
||||
|
||||
/*
|
||||
* a session with an SDP server
|
||||
*/
|
||||
typedef struct {
|
||||
int sock;
|
||||
int state;
|
||||
int local;
|
||||
int flags;
|
||||
uint16_t tid; /* Current transaction ID */
|
||||
void *priv;
|
||||
} sdp_session_t;
|
||||
|
||||
typedef enum {
|
||||
/*
|
||||
* Attributes are specified as individual elements
|
||||
*/
|
||||
SDP_ATTR_REQ_INDIVIDUAL = 1,
|
||||
/*
|
||||
* Attributes are specified as a range
|
||||
*/
|
||||
SDP_ATTR_REQ_RANGE
|
||||
} sdp_attrreq_type_t;
|
||||
|
||||
/*
|
||||
* When the pdu_id(type) is a sdp error response, check the status value
|
||||
* to figure out the error reason. For status values 0x0001-0x0006 check
|
||||
* Bluetooth SPEC. If the status is 0xffff, call sdp_get_error function
|
||||
* to get the real reason:
|
||||
* - wrong transaction ID(EPROTO)
|
||||
* - wrong PDU id or(EPROTO)
|
||||
* - I/O error
|
||||
*/
|
||||
typedef void sdp_callback_t(uint8_t type, uint16_t status, uint8_t *rsp, size_t size, void *udata);
|
||||
|
||||
/*
|
||||
* create an L2CAP connection to a Bluetooth device
|
||||
*
|
||||
* INPUT:
|
||||
*
|
||||
* bdaddr_t *src:
|
||||
* Address of the local device to use to make the connection
|
||||
* (or BDADDR_ANY)
|
||||
*
|
||||
* bdaddr_t *dst:
|
||||
* Address of the SDP server device
|
||||
*/
|
||||
sdp_session_t *sdp_connect(const bdaddr_t *src, const bdaddr_t *dst, uint32_t flags);
|
||||
int sdp_close(sdp_session_t *session);
|
||||
int sdp_get_socket(const sdp_session_t *session);
|
||||
|
||||
/*
|
||||
* SDP transaction: functions for asynchronous search.
|
||||
*/
|
||||
sdp_session_t *sdp_create(int sk, uint32_t flags);
|
||||
int sdp_get_error(sdp_session_t *session);
|
||||
int sdp_process(sdp_session_t *session);
|
||||
int sdp_set_notify(sdp_session_t *session, sdp_callback_t *func, void *udata);
|
||||
|
||||
int sdp_service_search_async(sdp_session_t *session, const sdp_list_t *search, uint16_t max_rec_num);
|
||||
int sdp_service_attr_async(sdp_session_t *session, uint32_t handle, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list);
|
||||
int sdp_service_search_attr_async(sdp_session_t *session, const sdp_list_t *search, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list);
|
||||
|
||||
uint16_t sdp_gen_tid(sdp_session_t *session);
|
||||
|
||||
/*
|
||||
* find all devices in the piconet
|
||||
*/
|
||||
int sdp_general_inquiry(inquiry_info *ii, int dev_num, int duration, uint8_t *found);
|
||||
|
||||
/* flexible extraction of basic attributes - Jean II */
|
||||
int sdp_get_int_attr(const sdp_record_t *rec, uint16_t attr, int *value);
|
||||
int sdp_get_string_attr(const sdp_record_t *rec, uint16_t attr, char *value, int valuelen);
|
||||
|
||||
/*
|
||||
* Basic sdp data functions
|
||||
*/
|
||||
sdp_data_t *sdp_data_alloc(uint8_t dtd, const void *value);
|
||||
sdp_data_t *sdp_data_alloc_with_length(uint8_t dtd, const void *value, uint32_t length);
|
||||
void sdp_data_free(sdp_data_t *data);
|
||||
sdp_data_t *sdp_data_get(const sdp_record_t *rec, uint16_t attr_id);
|
||||
|
||||
sdp_data_t *sdp_seq_alloc(void **dtds, void **values, int len);
|
||||
sdp_data_t *sdp_seq_alloc_with_length(void **dtds, void **values, int *length, int len);
|
||||
sdp_data_t *sdp_seq_append(sdp_data_t *seq, sdp_data_t *data);
|
||||
|
||||
int sdp_attr_add(sdp_record_t *rec, uint16_t attr, sdp_data_t *data);
|
||||
void sdp_attr_remove(sdp_record_t *rec, uint16_t attr);
|
||||
void sdp_attr_replace(sdp_record_t *rec, uint16_t attr, sdp_data_t *data);
|
||||
int sdp_set_uuidseq_attr(sdp_record_t *rec, uint16_t attr, sdp_list_t *seq);
|
||||
int sdp_get_uuidseq_attr(const sdp_record_t *rec, uint16_t attr, sdp_list_t **seqp);
|
||||
|
||||
/*
|
||||
* NOTE that none of the functions below will update the SDP server,
|
||||
* unless the {register, update}sdp_record_t() function is invoked.
|
||||
* All functions which return an integer value, return 0 on success
|
||||
* or -1 on failure.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Create an attribute and add it to the service record's attribute list.
|
||||
* This consists of the data type descriptor of the attribute,
|
||||
* the value of the attribute and the attribute identifier.
|
||||
*/
|
||||
int sdp_attr_add_new(sdp_record_t *rec, uint16_t attr, uint8_t dtd, const void *p);
|
||||
|
||||
/*
|
||||
* Set the information attributes of the service record.
|
||||
* The set of attributes comprises service name, description
|
||||
* and provider name
|
||||
*/
|
||||
void sdp_set_info_attr(sdp_record_t *rec, const char *name, const char *prov, const char *desc);
|
||||
|
||||
/*
|
||||
* Set the ServiceClassID attribute to the sequence specified by seq.
|
||||
* Note that the identifiers need to be in sorted order from the most
|
||||
* specific to the most generic service class that this service
|
||||
* conforms to.
|
||||
*/
|
||||
static inline int sdp_set_service_classes(sdp_record_t *rec, sdp_list_t *seq)
|
||||
{
|
||||
return sdp_set_uuidseq_attr(rec, SDP_ATTR_SVCLASS_ID_LIST, seq);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the service classes to which the service conforms.
|
||||
*
|
||||
* When set, the list contains elements of ServiceClassIdentifer(uint16_t)
|
||||
* ordered from most specific to most generic
|
||||
*/
|
||||
static inline int sdp_get_service_classes(const sdp_record_t *rec, sdp_list_t **seqp)
|
||||
{
|
||||
return sdp_get_uuidseq_attr(rec, SDP_ATTR_SVCLASS_ID_LIST, seqp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the BrowseGroupList attribute to the list specified by seq.
|
||||
*
|
||||
* A service can belong to one or more service groups
|
||||
* and the list comprises such group identifiers (UUIDs)
|
||||
*/
|
||||
static inline int sdp_set_browse_groups(sdp_record_t *rec, sdp_list_t *seq)
|
||||
{
|
||||
return sdp_set_uuidseq_attr(rec, SDP_ATTR_BROWSE_GRP_LIST, seq);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the access protocols of the record to those specified in proto
|
||||
*/
|
||||
int sdp_set_access_protos(sdp_record_t *rec, const sdp_list_t *proto);
|
||||
|
||||
/*
|
||||
* Set the additional access protocols of the record to those specified in proto
|
||||
*/
|
||||
int sdp_set_add_access_protos(sdp_record_t *rec, const sdp_list_t *proto);
|
||||
|
||||
/*
|
||||
* Get protocol port (i.e. PSM for L2CAP, Channel for RFCOMM)
|
||||
*/
|
||||
int sdp_get_proto_port(const sdp_list_t *list, int proto);
|
||||
|
||||
/*
|
||||
* Get protocol descriptor.
|
||||
*/
|
||||
sdp_data_t *sdp_get_proto_desc(sdp_list_t *list, int proto);
|
||||
|
||||
/*
|
||||
* Set the LanguageBase attributes to the values specified in list
|
||||
* (a linked list of sdp_lang_attr_t objects, one for each language in
|
||||
* which user-visible attributes are present).
|
||||
*/
|
||||
int sdp_set_lang_attr(sdp_record_t *rec, const sdp_list_t *list);
|
||||
|
||||
/*
|
||||
* Set the ServiceInfoTimeToLive attribute of the service.
|
||||
* This is the number of seconds that this record is guaranteed
|
||||
* not to change after being obtained by a client.
|
||||
*/
|
||||
static inline int sdp_set_service_ttl(sdp_record_t *rec, uint32_t ttl)
|
||||
{
|
||||
return sdp_attr_add_new(rec, SDP_ATTR_SVCINFO_TTL, SDP_UINT32, &ttl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the ServiceRecordState attribute of a service. This is
|
||||
* guaranteed to change if there is any kind of modification to
|
||||
* the record.
|
||||
*/
|
||||
static inline int sdp_set_record_state(sdp_record_t *rec, uint32_t state)
|
||||
{
|
||||
return sdp_attr_add_new(rec, SDP_ATTR_RECORD_STATE, SDP_UINT32, &state);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the ServiceID attribute of a service.
|
||||
*/
|
||||
void sdp_set_service_id(sdp_record_t *rec, uuid_t uuid);
|
||||
|
||||
/*
|
||||
* Set the GroupID attribute of a service
|
||||
*/
|
||||
void sdp_set_group_id(sdp_record_t *rec, uuid_t grouuuid);
|
||||
|
||||
/*
|
||||
* Set the ServiceAvailability attribute of a service.
|
||||
*
|
||||
* Note that this represents the relative availability
|
||||
* of the service: 0x00 means completely unavailable;
|
||||
* 0xFF means maximum availability.
|
||||
*/
|
||||
static inline int sdp_set_service_avail(sdp_record_t *rec, uint8_t avail)
|
||||
{
|
||||
return sdp_attr_add_new(rec, SDP_ATTR_SERVICE_AVAILABILITY, SDP_UINT8, &avail);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the profile descriptor list attribute of a record.
|
||||
*
|
||||
* Each element in the list is an object of type
|
||||
* sdp_profile_desc_t which is a definition of the
|
||||
* Bluetooth profile that this service conforms to.
|
||||
*/
|
||||
int sdp_set_profile_descs(sdp_record_t *rec, const sdp_list_t *desc);
|
||||
|
||||
/*
|
||||
* Set URL attributes of a record.
|
||||
*
|
||||
* ClientExecutableURL: a URL to a client's platform specific (WinCE,
|
||||
* PalmOS) executable code that can be used to access this service.
|
||||
*
|
||||
* DocumentationURL: a URL pointing to service documentation
|
||||
*
|
||||
* IconURL: a URL to an icon that can be used to represent this service.
|
||||
*
|
||||
* Note: pass NULL for any URLs that you don't want to set or remove
|
||||
*/
|
||||
void sdp_set_url_attr(sdp_record_t *rec, const char *clientExecURL, const char *docURL, const char *iconURL);
|
||||
|
||||
/*
|
||||
* a service search request.
|
||||
*
|
||||
* INPUT :
|
||||
*
|
||||
* sdp_list_t *search
|
||||
* list containing elements of the search
|
||||
* pattern. Each entry in the list is a UUID
|
||||
* of the service to be searched
|
||||
*
|
||||
* uint16_t max_rec_num
|
||||
* An integer specifying the maximum number of
|
||||
* entries that the client can handle in the response.
|
||||
*
|
||||
* OUTPUT :
|
||||
*
|
||||
* int return value
|
||||
* 0
|
||||
* The request completed successfully. This does not
|
||||
* mean the requested services were found
|
||||
* -1
|
||||
* The request completed unsuccessfully
|
||||
*
|
||||
* sdp_list_t *rsp_list
|
||||
* This variable is set on a successful return if there are
|
||||
* non-zero service handles. It is a singly linked list of
|
||||
* service record handles (uint16_t)
|
||||
*/
|
||||
int sdp_service_search_req(sdp_session_t *session, const sdp_list_t *search, uint16_t max_rec_num, sdp_list_t **rsp_list);
|
||||
|
||||
/*
|
||||
* a service attribute request.
|
||||
*
|
||||
* INPUT :
|
||||
*
|
||||
* uint32_t handle
|
||||
* The handle of the service for which the attribute(s) are
|
||||
* requested
|
||||
*
|
||||
* sdp_attrreq_type_t reqtype
|
||||
* Attribute identifiers are 16 bit unsigned integers specified
|
||||
* in one of 2 ways described below :
|
||||
* SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers
|
||||
* They are the actual attribute identifiers in ascending order
|
||||
*
|
||||
* SDP_ATTR_REQ_RANGE - 32bit identifier range
|
||||
* The high-order 16bits is the start of range
|
||||
* the low-order 16bits are the end of range
|
||||
* 0x0000 to 0xFFFF gets all attributes
|
||||
*
|
||||
* sdp_list_t *attrid_list
|
||||
* Singly linked list containing attribute identifiers desired.
|
||||
* Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
|
||||
* or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)
|
||||
*
|
||||
* OUTPUT :
|
||||
* int return value
|
||||
* 0
|
||||
* The request completed successfully. This does not
|
||||
* mean the requested services were found
|
||||
* -1
|
||||
* The request completed unsuccessfully due to a timeout
|
||||
*/
|
||||
sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list);
|
||||
|
||||
/*
|
||||
* This is a service search request combined with the service
|
||||
* attribute request. First a service class match is done and
|
||||
* for matching service, requested attributes are extracted
|
||||
*
|
||||
* INPUT :
|
||||
*
|
||||
* sdp_list_t *search
|
||||
* Singly linked list containing elements of the search
|
||||
* pattern. Each entry in the list is a UUID(DataTypeSDP_UUID16)
|
||||
* of the service to be searched
|
||||
*
|
||||
* AttributeSpecification attrSpec
|
||||
* Attribute identifiers are 16 bit unsigned integers specified
|
||||
* in one of 2 ways described below :
|
||||
* SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers
|
||||
* They are the actual attribute identifiers in ascending order
|
||||
*
|
||||
* SDP_ATTR_REQ_RANGE - 32bit identifier range
|
||||
* The high-order 16bits is the start of range
|
||||
* the low-order 16bits are the end of range
|
||||
* 0x0000 to 0xFFFF gets all attributes
|
||||
*
|
||||
* sdp_list_t *attrid_list
|
||||
* Singly linked list containing attribute identifiers desired.
|
||||
* Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
|
||||
* or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)
|
||||
*
|
||||
* OUTPUT :
|
||||
* int return value
|
||||
* 0
|
||||
* The request completed successfully. This does not
|
||||
* mean the requested services were found
|
||||
* -1
|
||||
* The request completed unsuccessfully due to a timeout
|
||||
*
|
||||
* sdp_list_t *rsp_list
|
||||
* This variable is set on a successful return to point to
|
||||
* service(s) found. Each element of this list is of type
|
||||
* sdp_record_t *.
|
||||
*/
|
||||
int sdp_service_search_attr_req(sdp_session_t *session, const sdp_list_t *search, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list, sdp_list_t **rsp_list);
|
||||
|
||||
/*
|
||||
* Allocate/free a service record and its attributes
|
||||
*/
|
||||
sdp_record_t *sdp_record_alloc(void);
|
||||
void sdp_record_free(sdp_record_t *rec);
|
||||
|
||||
/*
|
||||
* Register a service record.
|
||||
*
|
||||
* Note: It is the responsbility of the Service Provider to create the
|
||||
* record first and set its attributes using setXXX() methods.
|
||||
*
|
||||
* The service provider must then call sdp_record_register() to make
|
||||
* the service record visible to SDP clients. This function returns 0
|
||||
* on success or -1 on failure (and sets errno).
|
||||
*/
|
||||
int sdp_device_record_register_binary(sdp_session_t *session, bdaddr_t *device, uint8_t *data, uint32_t size, uint8_t flags, uint32_t *handle);
|
||||
int sdp_device_record_register(sdp_session_t *session, bdaddr_t *device, sdp_record_t *rec, uint8_t flags);
|
||||
int sdp_record_register(sdp_session_t *session, sdp_record_t *rec, uint8_t flags);
|
||||
|
||||
/*
|
||||
* Unregister a service record.
|
||||
*/
|
||||
int sdp_device_record_unregister_binary(sdp_session_t *session, bdaddr_t *device, uint32_t handle);
|
||||
int sdp_device_record_unregister(sdp_session_t *session, bdaddr_t *device, sdp_record_t *rec);
|
||||
int sdp_record_unregister(sdp_session_t *session, sdp_record_t *rec);
|
||||
|
||||
/*
|
||||
* Update an existing service record. (Calling this function
|
||||
* before a previous call to sdp_record_register() will result
|
||||
* in an error.)
|
||||
*/
|
||||
int sdp_device_record_update_binary(sdp_session_t *session, bdaddr_t *device, uint32_t handle, uint8_t *data, uint32_t size);
|
||||
int sdp_device_record_update(sdp_session_t *session, bdaddr_t *device, const sdp_record_t *rec);
|
||||
int sdp_record_update(sdp_session_t *sess, const sdp_record_t *rec);
|
||||
|
||||
void sdp_record_print(const sdp_record_t *rec);
|
||||
|
||||
/*
|
||||
* UUID functions
|
||||
*/
|
||||
uuid_t *sdp_uuid16_create(uuid_t *uuid, uint16_t data);
|
||||
uuid_t *sdp_uuid32_create(uuid_t *uuid, uint32_t data);
|
||||
uuid_t *sdp_uuid128_create(uuid_t *uuid, const void *data);
|
||||
int sdp_uuid16_cmp(const void *p1, const void *p2);
|
||||
int sdp_uuid128_cmp(const void *p1, const void *p2);
|
||||
int sdp_uuid_cmp(const void *p1, const void *p2);
|
||||
uuid_t *sdp_uuid_to_uuid128(const uuid_t *uuid);
|
||||
void sdp_uuid16_to_uuid128(uuid_t *uuid128, const uuid_t *uuid16);
|
||||
void sdp_uuid32_to_uuid128(uuid_t *uuid128, const uuid_t *uuid32);
|
||||
int sdp_uuid128_to_uuid(uuid_t *uuid);
|
||||
int sdp_uuid_to_proto(uuid_t *uuid);
|
||||
int sdp_uuid_extract(const uint8_t *buffer, int bufsize, uuid_t *uuid, int *scanned);
|
||||
void sdp_uuid_print(const uuid_t *uuid);
|
||||
|
||||
#define MAX_LEN_UUID_STR 37
|
||||
#define MAX_LEN_PROTOCOL_UUID_STR 8
|
||||
#define MAX_LEN_SERVICECLASS_UUID_STR 28
|
||||
#define MAX_LEN_PROFILEDESCRIPTOR_UUID_STR 28
|
||||
|
||||
int sdp_uuid2strn(const uuid_t *uuid, char *str, size_t n);
|
||||
int sdp_proto_uuid2strn(const uuid_t *uuid, char *str, size_t n);
|
||||
int sdp_svclass_uuid2strn(const uuid_t *uuid, char *str, size_t n);
|
||||
int sdp_profile_uuid2strn(const uuid_t *uuid, char *str, size_t n);
|
||||
|
||||
/*
|
||||
* In all the sdp_get_XXX(handle, XXX *xxx) functions below,
|
||||
* the XXX * is set to point to the value, should it exist
|
||||
* and 0 is returned. If the value does not exist, -1 is
|
||||
* returned and errno set to ENODATA.
|
||||
*
|
||||
* In all the methods below, the memory management rules are
|
||||
* simple. Don't free anything! The pointer returned, in the
|
||||
* case of constructed types, is a pointer to the contents
|
||||
* of the sdp_record_t.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Get the access protocols from the service record
|
||||
*/
|
||||
int sdp_get_access_protos(const sdp_record_t *rec, sdp_list_t **protos);
|
||||
|
||||
/*
|
||||
* Get the additional access protocols from the service record
|
||||
*/
|
||||
int sdp_get_add_access_protos(const sdp_record_t *rec, sdp_list_t **protos);
|
||||
|
||||
/*
|
||||
* Extract the list of browse groups to which the service belongs.
|
||||
* When set, seqp contains elements of GroupID (uint16_t)
|
||||
*/
|
||||
static inline int sdp_get_browse_groups(const sdp_record_t *rec, sdp_list_t **seqp)
|
||||
{
|
||||
return sdp_get_uuidseq_attr(rec, SDP_ATTR_BROWSE_GRP_LIST, seqp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract language attribute meta-data of the service record.
|
||||
* For each language in the service record, LangSeq has a struct of type
|
||||
* sdp_lang_attr_t.
|
||||
*/
|
||||
int sdp_get_lang_attr(const sdp_record_t *rec, sdp_list_t **langSeq);
|
||||
|
||||
/*
|
||||
* Extract the Bluetooth profile descriptor sequence from a record.
|
||||
* Each element in the list is of type sdp_profile_desc_t
|
||||
* which contains the UUID of the profile and its version number
|
||||
* (encoded as major and minor in the high-order 8bits
|
||||
* and low-order 8bits respectively of the uint16_t)
|
||||
*/
|
||||
int sdp_get_profile_descs(const sdp_record_t *rec, sdp_list_t **profDesc);
|
||||
|
||||
/*
|
||||
* Extract SDP server version numbers
|
||||
*
|
||||
* Note: that this is an attribute of the SDP server only and
|
||||
* contains a list of uint16_t each of which represent the
|
||||
* major and minor SDP version numbers supported by this server
|
||||
*/
|
||||
int sdp_get_server_ver(const sdp_record_t *rec, sdp_list_t **pVnumList);
|
||||
|
||||
int sdp_get_service_id(const sdp_record_t *rec, uuid_t *uuid);
|
||||
int sdp_get_group_id(const sdp_record_t *rec, uuid_t *uuid);
|
||||
int sdp_get_record_state(const sdp_record_t *rec, uint32_t *svcRecState);
|
||||
int sdp_get_service_avail(const sdp_record_t *rec, uint8_t *svcAvail);
|
||||
int sdp_get_service_ttl(const sdp_record_t *rec, uint32_t *svcTTLInfo);
|
||||
int sdp_get_database_state(const sdp_record_t *rec, uint32_t *svcDBState);
|
||||
|
||||
static inline int sdp_get_service_name(const sdp_record_t *rec, char *str, int len)
|
||||
{
|
||||
return sdp_get_string_attr(rec, SDP_ATTR_SVCNAME_PRIMARY, str, len);
|
||||
}
|
||||
|
||||
static inline int sdp_get_service_desc(const sdp_record_t *rec, char *str, int len)
|
||||
{
|
||||
return sdp_get_string_attr(rec, SDP_ATTR_SVCDESC_PRIMARY, str, len);
|
||||
}
|
||||
|
||||
static inline int sdp_get_provider_name(const sdp_record_t *rec, char *str, int len)
|
||||
{
|
||||
return sdp_get_string_attr(rec, SDP_ATTR_PROVNAME_PRIMARY, str, len);
|
||||
}
|
||||
|
||||
static inline int sdp_get_doc_url(const sdp_record_t *rec, char *str, int len)
|
||||
{
|
||||
return sdp_get_string_attr(rec, SDP_ATTR_DOC_URL, str, len);
|
||||
}
|
||||
|
||||
static inline int sdp_get_clnt_exec_url(const sdp_record_t *rec, char *str, int len)
|
||||
{
|
||||
return sdp_get_string_attr(rec, SDP_ATTR_CLNT_EXEC_URL, str, len);
|
||||
}
|
||||
|
||||
static inline int sdp_get_icon_url(const sdp_record_t *rec, char *str, int len)
|
||||
{
|
||||
return sdp_get_string_attr(rec, SDP_ATTR_ICON_URL, str, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the supported features
|
||||
* sf should be a list of list with each feature data
|
||||
* Returns 0 on success -1 on fail
|
||||
*/
|
||||
int sdp_set_supp_feat(sdp_record_t *rec, const sdp_list_t *sf);
|
||||
|
||||
/*
|
||||
* Get the supported features
|
||||
* seqp is set to a list of list with each feature data
|
||||
* Returns 0 on success, if an error occurred -1 is returned and errno is set
|
||||
*/
|
||||
int sdp_get_supp_feat(const sdp_record_t *rec, sdp_list_t **seqp);
|
||||
|
||||
sdp_record_t *sdp_extract_pdu(const uint8_t *pdata, int bufsize, int *scanned);
|
||||
sdp_record_t *sdp_copy_record(sdp_record_t *rec);
|
||||
|
||||
void sdp_data_print(sdp_data_t *data);
|
||||
void sdp_print_service_attr(sdp_list_t *alist);
|
||||
|
||||
int sdp_attrid_comp_func(const void *key1, const void *key2);
|
||||
|
||||
void sdp_set_seq_len(uint8_t *ptr, uint32_t length);
|
||||
void sdp_set_attrid(sdp_buf_t *pdu, uint16_t id);
|
||||
void sdp_append_to_pdu(sdp_buf_t *dst, sdp_data_t *d);
|
||||
void sdp_append_to_buf(sdp_buf_t *dst, uint8_t *data, uint32_t len);
|
||||
|
||||
int sdp_gen_pdu(sdp_buf_t *pdu, sdp_data_t *data);
|
||||
int sdp_gen_record_pdu(const sdp_record_t *rec, sdp_buf_t *pdu);
|
||||
|
||||
int sdp_extract_seqtype(const uint8_t *buf, int bufsize, uint8_t *dtdp, int *size);
|
||||
|
||||
sdp_data_t *sdp_extract_attr(const uint8_t *pdata, int bufsize, int *extractedLength, sdp_record_t *rec);
|
||||
|
||||
void sdp_pattern_add_uuid(sdp_record_t *rec, uuid_t *uuid);
|
||||
void sdp_pattern_add_uuidseq(sdp_record_t *rec, sdp_list_t *seq);
|
||||
|
||||
int sdp_send_req_w4_rsp(sdp_session_t *session, uint8_t *req, uint8_t *rsp, uint32_t reqsize, uint32_t *rspsize);
|
||||
|
||||
void sdp_add_lang_attr(sdp_record_t *rec);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SDP_LIB_H */
|
|
@ -1,181 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* BlueZ - Bluetooth protocol stack for Linux
|
||||
*
|
||||
* Copyright (C) 2011 Nokia Corporation
|
||||
* Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BLUETOOTH_UUID_H
|
||||
#define __BLUETOOTH_UUID_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define GENERIC_AUDIO_UUID "00001203-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define HSP_HS_UUID "00001108-0000-1000-8000-00805f9b34fb"
|
||||
#define HSP_AG_UUID "00001112-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define HFP_HS_UUID "0000111e-0000-1000-8000-00805f9b34fb"
|
||||
#define HFP_AG_UUID "0000111f-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define ADVANCED_AUDIO_UUID "0000110d-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define A2DP_SOURCE_UUID "0000110a-0000-1000-8000-00805f9b34fb"
|
||||
#define A2DP_SINK_UUID "0000110b-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define AVRCP_REMOTE_UUID "0000110e-0000-1000-8000-00805f9b34fb"
|
||||
#define AVRCP_TARGET_UUID "0000110c-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define PANU_UUID "00001115-0000-1000-8000-00805f9b34fb"
|
||||
#define NAP_UUID "00001116-0000-1000-8000-00805f9b34fb"
|
||||
#define GN_UUID "00001117-0000-1000-8000-00805f9b34fb"
|
||||
#define BNEP_SVC_UUID "0000000f-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define PNPID_UUID "00002a50-0000-1000-8000-00805f9b34fb"
|
||||
#define DEVICE_INFORMATION_UUID "0000180a-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define GATT_UUID "00001801-0000-1000-8000-00805f9b34fb"
|
||||
#define IMMEDIATE_ALERT_UUID "00001802-0000-1000-8000-00805f9b34fb"
|
||||
#define LINK_LOSS_UUID "00001803-0000-1000-8000-00805f9b34fb"
|
||||
#define TX_POWER_UUID "00001804-0000-1000-8000-00805f9b34fb"
|
||||
#define BATTERY_UUID "0000180f-0000-1000-8000-00805f9b34fb"
|
||||
#define SCAN_PARAMETERS_UUID "00001813-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define SAP_UUID "0000112D-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define HEART_RATE_UUID "0000180d-0000-1000-8000-00805f9b34fb"
|
||||
#define HEART_RATE_MEASUREMENT_UUID "00002a37-0000-1000-8000-00805f9b34fb"
|
||||
#define BODY_SENSOR_LOCATION_UUID "00002a38-0000-1000-8000-00805f9b34fb"
|
||||
#define HEART_RATE_CONTROL_POINT_UUID "00002a39-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define HEALTH_THERMOMETER_UUID "00001809-0000-1000-8000-00805f9b34fb"
|
||||
#define TEMPERATURE_MEASUREMENT_UUID "00002a1c-0000-1000-8000-00805f9b34fb"
|
||||
#define TEMPERATURE_TYPE_UUID "00002a1d-0000-1000-8000-00805f9b34fb"
|
||||
#define INTERMEDIATE_TEMPERATURE_UUID "00002a1e-0000-1000-8000-00805f9b34fb"
|
||||
#define MEASUREMENT_INTERVAL_UUID "00002a21-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define CYCLING_SC_UUID "00001816-0000-1000-8000-00805f9b34fb"
|
||||
#define CSC_MEASUREMENT_UUID "00002a5b-0000-1000-8000-00805f9b34fb"
|
||||
#define CSC_FEATURE_UUID "00002a5c-0000-1000-8000-00805f9b34fb"
|
||||
#define SENSOR_LOCATION_UUID "00002a5d-0000-1000-8000-00805f9b34fb"
|
||||
#define SC_CONTROL_POINT_UUID "00002a55-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define RFCOMM_UUID_STR "00000003-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define HDP_UUID "00001400-0000-1000-8000-00805f9b34fb"
|
||||
#define HDP_SOURCE_UUID "00001401-0000-1000-8000-00805f9b34fb"
|
||||
#define HDP_SINK_UUID "00001402-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define HID_UUID "00001124-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define DUN_GW_UUID "00001103-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define GAP_UUID "00001800-0000-1000-8000-00805f9b34fb"
|
||||
#define PNP_UUID "00001200-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define SPP_UUID "00001101-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define OBEX_SYNC_UUID "00001104-0000-1000-8000-00805f9b34fb"
|
||||
#define OBEX_OPP_UUID "00001105-0000-1000-8000-00805f9b34fb"
|
||||
#define OBEX_FTP_UUID "00001106-0000-1000-8000-00805f9b34fb"
|
||||
#define OBEX_PCE_UUID "0000112e-0000-1000-8000-00805f9b34fb"
|
||||
#define OBEX_PSE_UUID "0000112f-0000-1000-8000-00805f9b34fb"
|
||||
#define OBEX_PBAP_UUID "00001130-0000-1000-8000-00805f9b34fb"
|
||||
#define OBEX_MAS_UUID "00001132-0000-1000-8000-00805f9b34fb"
|
||||
#define OBEX_MNS_UUID "00001133-0000-1000-8000-00805f9b34fb"
|
||||
#define OBEX_MAP_UUID "00001134-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
/* GATT UUIDs section */
|
||||
#define GATT_PRIM_SVC_UUID 0x2800
|
||||
#define GATT_SND_SVC_UUID 0x2801
|
||||
#define GATT_INCLUDE_UUID 0x2802
|
||||
#define GATT_CHARAC_UUID 0x2803
|
||||
|
||||
/* GATT Characteristic Types */
|
||||
#define GATT_CHARAC_DEVICE_NAME 0x2A00
|
||||
#define GATT_CHARAC_APPEARANCE 0x2A01
|
||||
#define GATT_CHARAC_PERIPHERAL_PRIV_FLAG 0x2A02
|
||||
#define GATT_CHARAC_RECONNECTION_ADDRESS 0x2A03
|
||||
#define GATT_CHARAC_PERIPHERAL_PREF_CONN 0x2A04
|
||||
#define GATT_CHARAC_SERVICE_CHANGED 0x2A05
|
||||
#define GATT_CHARAC_SYSTEM_ID 0x2A23
|
||||
#define GATT_CHARAC_MODEL_NUMBER_STRING 0x2A24
|
||||
#define GATT_CHARAC_SERIAL_NUMBER_STRING 0x2A25
|
||||
#define GATT_CHARAC_FIRMWARE_REVISION_STRING 0x2A26
|
||||
#define GATT_CHARAC_HARDWARE_REVISION_STRING 0x2A27
|
||||
#define GATT_CHARAC_SOFTWARE_REVISION_STRING 0x2A28
|
||||
#define GATT_CHARAC_MANUFACTURER_NAME_STRING 0x2A29
|
||||
#define GATT_CHARAC_PNP_ID 0x2A50
|
||||
|
||||
/* GATT Characteristic Descriptors */
|
||||
#define GATT_CHARAC_EXT_PROPER_UUID 0x2900
|
||||
#define GATT_CHARAC_USER_DESC_UUID 0x2901
|
||||
#define GATT_CLIENT_CHARAC_CFG_UUID 0x2902
|
||||
#define GATT_SERVER_CHARAC_CFG_UUID 0x2903
|
||||
#define GATT_CHARAC_FMT_UUID 0x2904
|
||||
#define GATT_CHARAC_AGREG_FMT_UUID 0x2905
|
||||
#define GATT_CHARAC_VALID_RANGE_UUID 0x2906
|
||||
#define GATT_EXTERNAL_REPORT_REFERENCE 0x2907
|
||||
#define GATT_REPORT_REFERENCE 0x2908
|
||||
|
||||
typedef struct {
|
||||
enum {
|
||||
BT_UUID_UNSPEC = 0,
|
||||
BT_UUID16 = 16,
|
||||
BT_UUID32 = 32,
|
||||
BT_UUID128 = 128,
|
||||
} type;
|
||||
union {
|
||||
uint16_t u16;
|
||||
uint32_t u32;
|
||||
uint128_t u128;
|
||||
} value;
|
||||
} bt_uuid_t;
|
||||
|
||||
int bt_uuid_strcmp(const void *a, const void *b);
|
||||
|
||||
int bt_uuid16_create(bt_uuid_t *btuuid, uint16_t value);
|
||||
int bt_uuid32_create(bt_uuid_t *btuuid, uint32_t value);
|
||||
int bt_uuid128_create(bt_uuid_t *btuuid, uint128_t value);
|
||||
|
||||
int bt_uuid_cmp(const bt_uuid_t *uuid1, const bt_uuid_t *uuid2);
|
||||
void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst);
|
||||
|
||||
#define MAX_LEN_UUID_STR 37
|
||||
|
||||
int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n);
|
||||
int bt_string_to_uuid(bt_uuid_t *uuid, const char *string);
|
||||
|
||||
int bt_uuid_to_le(const bt_uuid_t *uuid, void *dst);
|
||||
|
||||
static inline int bt_uuid_len(const bt_uuid_t *uuid)
|
||||
{
|
||||
return uuid->type / 8;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __BLUETOOTH_UUID_H */
|
|
@ -1,38 +0,0 @@
|
|||
include ../Makefile.inc
|
||||
|
||||
MONITOR_OBJS = \
|
||||
../interface_control.c.o \
|
||||
../wifi_ht_channels.c.o \
|
||||
linux_wireless_control.c.o \
|
||||
linux_netlink_control.c.o \
|
||||
linux_nexmon_control.c.o \
|
||||
linux_wireless_rfkill.c.o \
|
||||
capture_linux_wifi.c.o
|
||||
|
||||
MONITOR_BIN = kismet_cap_linux_wifi
|
||||
|
||||
PCAPLIBS=@pcaplnk@
|
||||
NMLIBS=@NMLIBS@
|
||||
NETLINKLIBS=@NLLIBS@
|
||||
|
||||
all: $(MONITOR_BIN)
|
||||
|
||||
$(MONITOR_BIN): $(MONITOR_OBJS) $(patsubst %c.o,%c.d,$(MONITOR_OBJS)) ../libkismetdatasource.a
|
||||
$(CCLD) $(LDFLAGS) -o $(MONITOR_BIN) $(MONITOR_OBJS) ../libkismetdatasource.a $(PCAPLIBS) $(NMLIBS) $(NETLINKLIBS) $(DATASOURCE_LIBS)
|
||||
|
||||
clean:
|
||||
@-rm -f $(MONITOR_BIN)
|
||||
@-rm -f *.o
|
||||
@-rm -f *.d
|
||||
|
||||
%.c.o: %.c
|
||||
%.c.o : %.c %.c.d
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(GLIBCFLAGS) $(DBUSGLIBCFLAGS) -c $*.c -o $@
|
||||
|
||||
%.c.d: %.c
|
||||
$(CC) -MM $(CFLAGS) $(GLIBCFLAGS) $(DBUSGLIBCFLAGS) $(CPPFLAGS) $*.c | sed -e "s/\.o/\.c.o/" > $*.c.d
|
||||
|
||||
.PRECIOUS: %.c.d
|
||||
|
||||
include $(wildcard $(patsubst %c.o,%c.d,$(MONITOR_OBJS)))
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,830 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#if defined(HAVE_LIBNL20) || defined(HAVE_LIBNL30) || defined(HAVE_LIBNLTINY)
|
||||
#define HAVE_LIBNL_NG
|
||||
#endif
|
||||
|
||||
#ifdef SYS_LINUX
|
||||
|
||||
#ifdef HAVE_LINUX_NETLINK
|
||||
#include <sys/types.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
#ifdef HAVE_LIBNLTINY
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include <netlink/genl/genl.h>
|
||||
#include <netlink/genl/family.h>
|
||||
#include <netlink/genl/ctrl.h>
|
||||
#include <netlink/msg.h>
|
||||
#include <netlink/attr.h>
|
||||
|
||||
#include "../nl80211.h"
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "linux_netlink_control.h"
|
||||
#include "../wifi_ht_channels.h"
|
||||
|
||||
// Libnl1->Libnl2 compatability mode since the API changed, cribbed from 'iw'
|
||||
#if defined(HAVE_LIBNL10)
|
||||
|
||||
#define nl_sock nl_handle
|
||||
|
||||
static inline struct nl_handle *nl_socket_alloc(void) {
|
||||
return nl_handle_alloc();
|
||||
}
|
||||
|
||||
static inline void nl_socket_free(struct nl_sock *h) {
|
||||
nl_handle_destroy(h);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
unsigned int mac80211_chan_to_freq(unsigned int in_chan) {
|
||||
/* 802.11 channels to frequency; if it looks like a frequency, return as
|
||||
* pure frequency; derived from iwconfig */
|
||||
|
||||
if (in_chan > 250)
|
||||
return in_chan;
|
||||
|
||||
if (in_chan == 14)
|
||||
return 2484;
|
||||
else if (in_chan < 14)
|
||||
return 2407 + in_chan * 5;
|
||||
else if (in_chan >= 182 && in_chan <= 196)
|
||||
return 4000 + in_chan * 5;
|
||||
else
|
||||
return 5000 + in_chan * 5;
|
||||
|
||||
return in_chan;
|
||||
}
|
||||
|
||||
unsigned int mac80211_freq_to_chan(unsigned int in_freq) {
|
||||
if (in_freq < 250)
|
||||
return in_freq;
|
||||
|
||||
/* revamped from iw */
|
||||
if (in_freq == 2484)
|
||||
return 14;
|
||||
|
||||
if (in_freq < 2484)
|
||||
return (in_freq - 2407) / 5;
|
||||
|
||||
return in_freq / 5 - 1000;
|
||||
}
|
||||
|
||||
int mac80211_connect(const char *interface, void **nl_sock,
|
||||
int *nl80211_id, int *if_index, char *errstr) {
|
||||
#ifndef HAVE_LINUX_NETLINK
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"cannot connect to netlink; not compiled with netlink "
|
||||
"support. Check the output of ./configure for more information");
|
||||
return -1;
|
||||
#else
|
||||
|
||||
if ((*if_index = if_nametoindex(interface)) < 0) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"cannot connect to netlink: Could not find interface '%s'", interface);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*nl_sock = nl_socket_alloc();
|
||||
if (!nl_sock) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"unable to connect to netlink: could not allocate netlink socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (genl_connect(*nl_sock)) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"unable to connect to netlink: could not connect to generic netlink");
|
||||
return -1;
|
||||
nl_socket_free(*nl_sock);
|
||||
}
|
||||
|
||||
*nl80211_id = genl_ctrl_resolve(*nl_sock, "nl80211");
|
||||
if (nl80211_id < 0) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"unable to connect to netlink: could not resolve nl80211");
|
||||
nl_socket_free(*nl_sock);
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void mac80211_disconnect(void *nl_sock) {
|
||||
#ifdef HAVE_LINUX_NETLINK
|
||||
nl_socket_free(nl_sock);
|
||||
#endif
|
||||
}
|
||||
|
||||
int mac80211_create_monitor_vif(const char *interface, const char *newinterface,
|
||||
unsigned int *in_flags, unsigned int flags_sz, char *errstr) {
|
||||
#ifndef HAVE_LINUX_NETLINK
|
||||
snprintf(errstr, STATUS_MAX, "Kismet was not compiled with netlink/mac80211 "
|
||||
"support, check the output of ./configure for why");
|
||||
return -1;
|
||||
#else
|
||||
|
||||
void *nl_sock;
|
||||
int nl80211_id;
|
||||
|
||||
struct nl_msg *msg;
|
||||
struct nl_msg *flags;
|
||||
|
||||
unsigned int x;
|
||||
|
||||
if (if_nametoindex(newinterface) > 0)
|
||||
return 1;
|
||||
|
||||
nl_sock = nl_socket_alloc();
|
||||
if (!nl_sock) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"unable to create monitor vif %s:%s, unable to allocate netlink socket",
|
||||
interface, newinterface);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (genl_connect(nl_sock)) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"unable to create monitor vif %s:%s, unable to connect generic netlink",
|
||||
interface, newinterface);
|
||||
nl_socket_free(nl_sock);
|
||||
}
|
||||
|
||||
nl80211_id = genl_ctrl_resolve(nl_sock, "nl80211");
|
||||
if (nl80211_id < 0) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"unable to create monitor vif %s:%s, unable to resolve nl80211",
|
||||
interface, newinterface);
|
||||
nl_socket_free(nl_sock);
|
||||
}
|
||||
|
||||
if ((msg = nlmsg_alloc()) == NULL) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"unable to create monitor vif %s:%s, unable to allocate nl80211 "
|
||||
"message", interface, newinterface);
|
||||
nl_socket_free(nl_sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((flags = nlmsg_alloc()) == NULL) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"unable to create monitor vif %s:%s, unable to allocate nl80211 flags",
|
||||
interface, newinterface);
|
||||
nl_socket_free(nl_sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
genlmsg_put(msg, 0, 0, nl80211_id, 0, 0, NL80211_CMD_NEW_INTERFACE, 0);
|
||||
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(interface));
|
||||
NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, newinterface);
|
||||
NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
|
||||
|
||||
for (x = 0; x < flags_sz; x++) {
|
||||
NLA_PUT_FLAG(flags, in_flags[x]);
|
||||
}
|
||||
|
||||
if (flags_sz > 0)
|
||||
nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
|
||||
|
||||
if (nl_send_auto_complete(nl_sock, msg) < 0 || nl_wait_for_ack(nl_sock) < 0) {
|
||||
nla_put_failure:
|
||||
snprintf(errstr, STATUS_MAX, "failed to create monitor interface %s:%s",
|
||||
interface, newinterface);
|
||||
nl_socket_free(nl_sock);
|
||||
nlmsg_free(msg);
|
||||
nlmsg_free(flags);
|
||||
return -1;
|
||||
}
|
||||
|
||||
nl_socket_free(nl_sock);
|
||||
nlmsg_free(msg);
|
||||
nlmsg_free(flags);
|
||||
|
||||
if (if_nametoindex(newinterface) <= 0) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"creating a monitor interface for %s:%s worked, but couldn't"
|
||||
"find that interface after creation.", interface, newinterface);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int mac80211_set_channel_cache(int ifindex, void *nl_sock,
|
||||
int nl80211_id, int channel, unsigned int chmode, char *errstr) {
|
||||
#ifndef HAVE_LINUX_NETLINK
|
||||
snprintf(errstr, STATUS_MAX, "Kismet was not compiled with netlink/mac80211 "
|
||||
"support, check the output of ./configure for why");
|
||||
return -1;
|
||||
#else
|
||||
struct nl_msg *msg;
|
||||
int ret = 0;
|
||||
|
||||
if (chmode >= 4) {
|
||||
snprintf(errstr, STATUS_MAX, "unable to set channel: invalid channel mode");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((msg = nlmsg_alloc()) == NULL) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"unable to set channel: unable to allocate mac80211 control message.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
genlmsg_put(msg, 0, 0, nl80211_id, 0, 0, NL80211_CMD_SET_WIPHY, 0);
|
||||
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
|
||||
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, mac80211_chan_to_freq(channel));
|
||||
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, chmode);
|
||||
|
||||
if ((ret = nl_send_auto_complete(nl_sock, msg)) >= 0) {
|
||||
if ((ret = nl_wait_for_ack(nl_sock)) < 0)
|
||||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
nlmsg_free(msg);
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"unable to set channel %u/%u mode %u via mac80211: "
|
||||
"error code %d", channel, mac80211_chan_to_freq(channel), chmode, ret);
|
||||
nlmsg_free(msg);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
int mac80211_set_channel(const char *interface, int channel,
|
||||
unsigned int chmode, char *errstr) {
|
||||
#ifndef HAVE_LINUX_NETLINK
|
||||
snprintf(errstr, STATUS_MAX, "Kismet was not compiled with netlink/mac80211 "
|
||||
"support, check the output of ./configure for why");
|
||||
return -1;
|
||||
#else
|
||||
void *nl_sock;
|
||||
int nl80211_id;
|
||||
int ifidx;
|
||||
|
||||
if (mac80211_connect(interface, &nl_sock, &nl80211_id, &ifidx, errstr) < 0)
|
||||
return -1;
|
||||
|
||||
int ret =
|
||||
mac80211_set_channel_cache(ifidx, nl_sock, nl80211_id, channel, chmode, errstr);
|
||||
|
||||
mac80211_disconnect(nl_sock);
|
||||
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
int mac80211_set_frequency_cache(int ifindex, void *nl_sock, int nl80211_id,
|
||||
unsigned int control_freq, unsigned int chan_width,
|
||||
unsigned int center_freq1, unsigned int center_freq2,
|
||||
char *errstr) {
|
||||
#ifndef HAVE_LINUX_NETLINK
|
||||
snprintf(errstr, STATUS_MAX, "Kismet was not compiled with netlink/mac80211 "
|
||||
"support, check the output of ./configure for why");
|
||||
return -1;
|
||||
#else
|
||||
struct nl_msg *msg;
|
||||
int ret = 0;
|
||||
|
||||
if ((msg = nlmsg_alloc()) == NULL) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"unable to set channel/frequency: unable to allocate "
|
||||
"mac80211 control message.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
genlmsg_put(msg, 0, 0, nl80211_id, 0, 0, NL80211_CMD_SET_WIPHY, 0);
|
||||
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
|
||||
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ,
|
||||
mac80211_chan_to_freq(control_freq));
|
||||
NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, chan_width);
|
||||
|
||||
switch (chan_width) {
|
||||
case NL80211_CHAN_WIDTH_20_NOHT:
|
||||
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_NO_HT);
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_20:
|
||||
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
|
||||
break;
|
||||
case NL80211_CHAN_WIDTH_40:
|
||||
if (control_freq > center_freq1)
|
||||
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40MINUS);
|
||||
else
|
||||
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT40PLUS);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (center_freq1 != 0) {
|
||||
NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1,
|
||||
mac80211_chan_to_freq(center_freq1));
|
||||
}
|
||||
|
||||
if ((ret = nl_send_auto_complete(nl_sock, msg)) >= 0) {
|
||||
if ((ret = nl_wait_for_ack(nl_sock)) < 0)
|
||||
goto nla_put_failure;
|
||||
}
|
||||
|
||||
nlmsg_free(msg);
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"unable to set frequency %u %u %u via mac80211: error code %d",
|
||||
control_freq, chan_width, center_freq1, ret);
|
||||
nlmsg_free(msg);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
int mac80211_set_frequency(const char *interface,
|
||||
unsigned int control_freq, unsigned int chan_width,
|
||||
unsigned int center_freq1, unsigned int center_freq2,
|
||||
char *errstr) {
|
||||
#ifndef HAVE_LINUX_NETLINK
|
||||
snprintf(errstr, STATUS_MAX, "Kismet was not compiled with netlink/mac80211 "
|
||||
"support, check the output of ./configure for why");
|
||||
return -1;
|
||||
#else
|
||||
void *nl_sock;
|
||||
int ifidx;
|
||||
int nl80211_id;
|
||||
|
||||
if (mac80211_connect(interface, &nl_sock, &nl80211_id, &ifidx, errstr) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret =
|
||||
mac80211_set_frequency_cache(ifidx, nl_sock, nl80211_id,
|
||||
control_freq, chan_width, center_freq1, center_freq2, errstr);
|
||||
|
||||
mac80211_disconnect(nl_sock);
|
||||
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
struct nl80211_channel_list {
|
||||
char *channel;
|
||||
struct nl80211_channel_list *next;
|
||||
};
|
||||
|
||||
struct nl80211_channel_block {
|
||||
char *phyname;
|
||||
|
||||
int nfreqs;
|
||||
unsigned int extended_flags;
|
||||
|
||||
struct nl80211_channel_list *channel_list;
|
||||
struct nl80211_channel_list *chan_list_last;
|
||||
};
|
||||
|
||||
|
||||
#ifdef HAVE_LINUX_NETLINK
|
||||
/* Really ugly non-thread-safe (but we don't thread this ever) non-thread-safe way
|
||||
* to pass HT20 behavior down into the callback builder, because we don't really
|
||||
* want to rewrite the whole thing into a multi-list pass
|
||||
*/
|
||||
unsigned int glob_freqlist_default_ht20 = 0;
|
||||
unsigned int glob_freqlist_expand_ht20 = 0;
|
||||
|
||||
static int nl80211_freqlist_cb(struct nl_msg *msg, void *arg) {
|
||||
struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
|
||||
struct genlmsghdr *gnlh = (struct genlmsghdr *) nlmsg_data(nlmsg_hdr(msg));
|
||||
struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
|
||||
struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
|
||||
struct nlattr *nl_band, *nl_freq;
|
||||
int rem_band, rem_freq;
|
||||
uint32_t freq;
|
||||
struct nl80211_channel_block *chanb = (struct nl80211_channel_block *) arg;
|
||||
char channel_str[32];
|
||||
int band_ht40, band_ht80, band_ht160;
|
||||
unsigned int hti;
|
||||
|
||||
struct nl80211_channel_list *chan_list_new;
|
||||
|
||||
nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
|
||||
genlmsg_attrlen(gnlh, 0), NULL);
|
||||
|
||||
if (tb_msg[NL80211_ATTR_WIPHY_NAME]) {
|
||||
if (strcmp(nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME]), chanb->phyname) != 0) {
|
||||
return NL_SKIP;
|
||||
}
|
||||
}
|
||||
|
||||
if (tb_msg[NL80211_ATTR_WIPHY_BANDS]) {
|
||||
nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
|
||||
band_ht40 = band_ht80 = band_ht160 = 0;
|
||||
|
||||
nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
|
||||
nla_len(nl_band), NULL);
|
||||
|
||||
/* If we have a HT capability field, examine it for HT40 */
|
||||
if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
|
||||
__u16 cap = nla_get_u16(tb_band[NL80211_BAND_ATTR_HT_CAPA]);
|
||||
|
||||
/* bit 1 is the HT40 bit */
|
||||
if (cap & (1 << 1))
|
||||
band_ht40 = 1;
|
||||
}
|
||||
|
||||
/* If we have a VHT field, we can assume we have HT80 and then we need
|
||||
* to examine ht160.
|
||||
* TODO: figure out 160 80+80; do all devices that support 80+80 support
|
||||
* 160? For now we assume they do...
|
||||
*/
|
||||
if (tb_band[NL80211_BAND_ATTR_VHT_CAPA]) {
|
||||
band_ht80 = 1;
|
||||
|
||||
__u16 cap = nla_get_u32(tb_band[NL80211_BAND_ATTR_VHT_CAPA]);
|
||||
|
||||
if (((cap >> 2) & 3) == 1) {
|
||||
band_ht160 = 1;
|
||||
} else if (((cap >> 2) & 3) == 2) {
|
||||
fprintf(stderr, "debug - your device supports 160(80+80) mode\n");
|
||||
band_ht160 = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// fprintf(stderr, "debug - %u %u %u\n", band_ht40, band_ht80, band_ht160);
|
||||
|
||||
if (tb_band[NL80211_BAND_ATTR_FREQS]) {
|
||||
nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
|
||||
nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
|
||||
nla_len(nl_freq), NULL);
|
||||
|
||||
if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
|
||||
continue;
|
||||
|
||||
if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
|
||||
continue;
|
||||
|
||||
/* We've got at least one actual frequency */
|
||||
freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
|
||||
|
||||
chan_list_new = (struct nl80211_channel_list *) malloc(sizeof(struct nl80211_channel_list));
|
||||
|
||||
/* Default to HT20 if we support HT and are always using it, otherwise default to
|
||||
* basic channels */
|
||||
if ((chanb->extended_flags & MAC80211_GET_HT) && glob_freqlist_default_ht20)
|
||||
snprintf(channel_str, 32, "%uHT20", mac80211_freq_to_chan(freq));
|
||||
else
|
||||
snprintf(channel_str, 32, "%u", mac80211_freq_to_chan(freq));
|
||||
|
||||
chan_list_new->channel = strdup(channel_str);
|
||||
|
||||
chan_list_new->next = NULL;
|
||||
chanb->nfreqs++;
|
||||
chanb->chan_list_last->next = chan_list_new;
|
||||
chanb->chan_list_last = chan_list_new;
|
||||
|
||||
/* If we support HT, and expand HT20 instead of default to it, add a HT20 channel */
|
||||
if ((chanb->extended_flags & MAC80211_GET_HT) && !glob_freqlist_default_ht20 &&
|
||||
glob_freqlist_expand_ht20) {
|
||||
|
||||
chan_list_new = (struct nl80211_channel_list *) malloc(sizeof(struct nl80211_channel_list));
|
||||
snprintf(channel_str, 32, "%uHT20", mac80211_freq_to_chan(freq));
|
||||
chan_list_new->channel = strdup(channel_str);
|
||||
|
||||
chan_list_new->next = NULL;
|
||||
chanb->nfreqs++;
|
||||
chanb->chan_list_last->next = chan_list_new;
|
||||
chanb->chan_list_last = chan_list_new;
|
||||
}
|
||||
|
||||
/* Look us up in the wifi_ht_channels list and add channels if we
|
||||
* need to add HT capabilities. We could convert this to a channel
|
||||
* but it's better to do a frequency lookup */
|
||||
for (hti = 0; hti < MAX_WIFI_HT_CHANNEL; hti++) {
|
||||
if (wifi_ht_channels[hti].freq == freq) {
|
||||
if (band_ht40 && (chanb->extended_flags & MAC80211_GET_HT)) {
|
||||
if (wifi_ht_channels[hti].flags & WIFI_HT_HT40MINUS) {
|
||||
chan_list_new = (struct nl80211_channel_list *) malloc(sizeof(struct nl80211_channel_list));
|
||||
snprintf(channel_str, 32,
|
||||
"%uHT40-", mac80211_freq_to_chan(freq));
|
||||
chan_list_new->channel = strdup(channel_str);
|
||||
|
||||
chan_list_new->next = NULL;
|
||||
chanb->nfreqs++;
|
||||
chanb->chan_list_last->next = chan_list_new;
|
||||
chanb->chan_list_last = chan_list_new;
|
||||
}
|
||||
|
||||
if (wifi_ht_channels[hti].flags & WIFI_HT_HT40PLUS) {
|
||||
chan_list_new = (struct nl80211_channel_list *) malloc(sizeof(struct nl80211_channel_list));
|
||||
|
||||
snprintf(channel_str, 32,
|
||||
"%uHT40+", mac80211_freq_to_chan(freq));
|
||||
chan_list_new->channel = strdup(channel_str);
|
||||
|
||||
chan_list_new->next = NULL;
|
||||
chanb->nfreqs++;
|
||||
chanb->chan_list_last->next = chan_list_new;
|
||||
chanb->chan_list_last = chan_list_new;
|
||||
}
|
||||
}
|
||||
|
||||
if (band_ht80 && wifi_ht_channels[hti].flags & WIFI_HT_HT80 &&
|
||||
(chanb->extended_flags & MAC80211_GET_VHT)) {
|
||||
chan_list_new = (struct nl80211_channel_list *) malloc(sizeof(struct nl80211_channel_list));
|
||||
snprintf(channel_str, 32,
|
||||
"%uVHT80", mac80211_freq_to_chan(freq));
|
||||
chan_list_new->channel = strdup(channel_str);
|
||||
|
||||
chan_list_new->next = NULL;
|
||||
chanb->nfreqs++;
|
||||
chanb->chan_list_last->next = chan_list_new;
|
||||
chanb->chan_list_last = chan_list_new;
|
||||
}
|
||||
|
||||
if (band_ht160 && wifi_ht_channels[hti].flags & WIFI_HT_HT160 &&
|
||||
(chanb->extended_flags & MAC80211_GET_VHT)) {
|
||||
chan_list_new = (struct nl80211_channel_list *) malloc(sizeof(struct nl80211_channel_list));
|
||||
snprintf(channel_str, 32,
|
||||
"%uVHT160", mac80211_freq_to_chan(freq));
|
||||
chan_list_new->channel = strdup(channel_str);
|
||||
|
||||
chan_list_new->next = NULL;
|
||||
chanb->nfreqs++;
|
||||
chanb->chan_list_last->next = chan_list_new;
|
||||
chanb->chan_list_last = chan_list_new;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NL_SKIP;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_NETLINK
|
||||
static int nl80211_error_cb(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) {
|
||||
int *ret = (int *) arg;
|
||||
*ret = err->error;
|
||||
return NL_STOP;
|
||||
}
|
||||
|
||||
static int nl80211_finish_cb(struct nl_msg *msg, void *arg) {
|
||||
int *ret = (int *) arg;
|
||||
*ret = 0;
|
||||
return NL_SKIP;
|
||||
}
|
||||
|
||||
static int nl80211_ack_cb(struct nl_msg *msg, void *arg) {
|
||||
int *ret = arg;
|
||||
*ret = 0;
|
||||
return NL_STOP;
|
||||
}
|
||||
#endif
|
||||
|
||||
int mac80211_get_chanlist(const char *interface, unsigned int extended_flags, char *errstr,
|
||||
unsigned int default_ht20, unsigned int expand_ht20,
|
||||
char ***ret_chan_list, size_t *ret_num_chans) {
|
||||
struct nl80211_channel_block cblock = {
|
||||
.phyname = NULL,
|
||||
.nfreqs = 0,
|
||||
.channel_list = NULL,
|
||||
.chan_list_last = NULL
|
||||
};
|
||||
|
||||
unsigned int num_freq;
|
||||
struct nl80211_channel_list *chan_list_cur, *chan_list_old;
|
||||
|
||||
#ifndef HAVE_LINUX_NETLINK
|
||||
snprintf(errstr, STATUS_MAX, "Kismet was not compiled with netlink/nl80211 "
|
||||
"support, check the output of ./configure for why");
|
||||
return -1;
|
||||
#else
|
||||
|
||||
void *nl_sock;
|
||||
int nl80211_id;
|
||||
|
||||
struct nl_cb *cb;
|
||||
int err;
|
||||
struct nl_msg *msg;
|
||||
|
||||
/* Set the globals */
|
||||
glob_freqlist_default_ht20 = default_ht20;
|
||||
glob_freqlist_expand_ht20 = expand_ht20;
|
||||
|
||||
cblock.extended_flags = extended_flags;
|
||||
|
||||
cblock.phyname = mac80211_find_parent(interface);
|
||||
if (strlen(cblock.phyname) == 0) {
|
||||
if (if_nametoindex(interface) <= 0) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"failed to get channels from interface '%s': interface does "
|
||||
"not exist.", interface);
|
||||
free(cblock.phyname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"failed to find parent phy interface for interface '%s': interface "
|
||||
"may not be a mac80211 wifi device?", interface);
|
||||
free(cblock.phyname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
nl_sock = nl_socket_alloc();
|
||||
if (!nl_sock) {
|
||||
snprintf(errstr, STATUS_MAX, "FATAL: Failed to allocate netlink socket");
|
||||
free(cblock.phyname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (genl_connect(nl_sock)) {
|
||||
snprintf(errstr, STATUS_MAX, "FATAL: Failed to connect to generic netlink");
|
||||
nl_socket_free(nl_sock);
|
||||
free(cblock.phyname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
nl80211_id = genl_ctrl_resolve(nl_sock, "nl80211");
|
||||
if (nl80211_id < 0) {
|
||||
snprintf(errstr, STATUS_MAX, "FATAL: Failed to resolve nl80211");
|
||||
nl_socket_free(nl_sock);
|
||||
free(cblock.phyname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
msg = nlmsg_alloc();
|
||||
|
||||
cb = nl_cb_alloc(NL_CB_DEFAULT);
|
||||
|
||||
err = 1;
|
||||
|
||||
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_freqlist_cb, &cblock);
|
||||
nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, nl80211_ack_cb, &err);
|
||||
nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, nl80211_finish_cb, &err);
|
||||
nl_cb_err(cb, NL_CB_CUSTOM, nl80211_error_cb, &err);
|
||||
|
||||
genlmsg_put(msg, 0, 0, nl80211_id, 0, NLM_F_DUMP, NL80211_CMD_GET_WIPHY, 0);
|
||||
|
||||
/* Initialize the empty first channel list item */
|
||||
cblock.channel_list = (struct nl80211_channel_list *) malloc(sizeof(struct nl80211_channel_list));
|
||||
cblock.channel_list->channel = NULL;
|
||||
cblock.channel_list->next = NULL;
|
||||
cblock.chan_list_last = cblock.channel_list;
|
||||
|
||||
if (nl_send_auto_complete((struct nl_sock *) nl_sock, msg) < 0) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"failed to fetch channels from interface '%s': failed to "
|
||||
"write netlink command", interface);
|
||||
nlmsg_free(msg);
|
||||
nl_cb_put(cb);
|
||||
nl_socket_free(nl_sock);
|
||||
free(cblock.phyname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (err)
|
||||
nl_recvmsgs((struct nl_sock *) nl_sock, cb);
|
||||
|
||||
nl_cb_put(cb);
|
||||
nlmsg_free(msg);
|
||||
nl_socket_free(nl_sock);
|
||||
|
||||
/* Convert our linked list into a channel block */
|
||||
|
||||
(*ret_num_chans) = cblock.nfreqs;
|
||||
(*ret_chan_list) = malloc(sizeof(char *) * cblock.nfreqs);
|
||||
|
||||
num_freq = 0;
|
||||
|
||||
/* Skip the first item which is our placeholder */
|
||||
chan_list_cur = cblock.channel_list->next;
|
||||
|
||||
while (chan_list_cur != NULL && num_freq < cblock.nfreqs) {
|
||||
/* Use the dup'd string directly */
|
||||
(*ret_chan_list)[num_freq++] = chan_list_cur->channel;
|
||||
|
||||
// fprintf(stderr, "debug - %u %s\n", num_freq, chan_list_cur->channel);
|
||||
|
||||
/* Shuffle the pointers */
|
||||
chan_list_old = chan_list_cur;
|
||||
chan_list_cur = chan_list_cur->next;
|
||||
free(chan_list_old);
|
||||
}
|
||||
|
||||
/* If we didn't process all the channels before we hit the end of the list... */
|
||||
if (chan_list_cur != NULL || num_freq != cblock.nfreqs) {
|
||||
fprintf(stderr, "ERROR - linux_netlink_control miscalculated the number of "
|
||||
"channels somehow...\n");
|
||||
|
||||
/* Clean up list overrun */
|
||||
while (chan_list_cur != NULL) {
|
||||
chan_list_old = chan_list_cur;
|
||||
chan_list_cur = chan_list_cur->next;
|
||||
free(chan_list_old);
|
||||
}
|
||||
|
||||
/* Clean up list underrun */
|
||||
for ( ; num_freq < cblock.nfreqs; num_freq++) {
|
||||
(*ret_chan_list)[num_freq] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* remove the list head ptr */
|
||||
free(cblock.channel_list);
|
||||
/* Remove the phyname */
|
||||
free(cblock.phyname);
|
||||
|
||||
// (*ret_chan_list)[0] = strdup("45");
|
||||
|
||||
return (*ret_num_chans);
|
||||
#endif
|
||||
}
|
||||
|
||||
char *mac80211_find_parent(const char *interface) {
|
||||
DIR *devdir;
|
||||
struct dirent *devfile;
|
||||
char dirpath[2048];
|
||||
char *dev;
|
||||
|
||||
snprintf(dirpath, 2048, "/sys/class/net/%s/phy80211/device", interface);
|
||||
|
||||
if ((devdir = opendir(dirpath)) == NULL)
|
||||
return strdup("");
|
||||
|
||||
while ((devfile = readdir(devdir)) != NULL) {
|
||||
if (strlen(devfile->d_name) < 9)
|
||||
continue;
|
||||
|
||||
if (strncmp("ieee80211:phy", devfile->d_name, 13) == 0) {
|
||||
dev = strdup(devfile->d_name + 10);
|
||||
closedir(devdir);
|
||||
return dev;
|
||||
}
|
||||
|
||||
if (strncmp("ieee80211", devfile->d_name, 9) == 0) {
|
||||
DIR *ieeedir;
|
||||
struct dirent *ieeefile;
|
||||
|
||||
snprintf(dirpath, 2048, "/sys/class/net/%s/phy80211/device/ieee80211",
|
||||
interface);
|
||||
|
||||
if ((ieeedir = opendir(dirpath)) != NULL) {
|
||||
while ((ieeefile = readdir(ieeedir)) != NULL) {
|
||||
if (strncmp("phy", ieeefile->d_name, 3) == 0) {
|
||||
dev = strdup(ieeefile->d_name);
|
||||
|
||||
closedir(ieeedir);
|
||||
closedir(devdir);
|
||||
|
||||
return dev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ieeedir != NULL)
|
||||
closedir(ieeedir);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(devdir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* linux */
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#ifndef __LINUX_NETLINK_CONFIG__
|
||||
#define __LINUX_NETLINK_CONFIG__
|
||||
|
||||
/* Use local copy of nl80211.h */
|
||||
#include "../nl80211.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* Create a monitor vif using mac80211, based on existing interface *interface
|
||||
* and named *newinterface.
|
||||
*
|
||||
* Flags must be from nl80211_mntr_flags from nl80211.h
|
||||
*
|
||||
* errstr must be allocated by the caller and be able to hold STATUS_MAX
|
||||
* characters.
|
||||
*
|
||||
* Returns:
|
||||
* -1 Error
|
||||
* 0 Success
|
||||
*/
|
||||
int mac80211_create_monitor_vif(const char *interface, const char *newinterface,
|
||||
unsigned int *flags, unsigned int flags_sz, char *errstr);
|
||||
|
||||
/* Connect to nl80211 and resolve the genl and nl80211 ids; this generates the
|
||||
* cache state needed for channel control.
|
||||
*
|
||||
* **nl_sock is allocated by the function, and must be freed with mac80211_nl_disconnect
|
||||
* *nl80211_id is populated by the function
|
||||
* *if_index is populated with the interface index of the provided interface
|
||||
*
|
||||
* Returns:
|
||||
* -1 Error
|
||||
* 0 Success
|
||||
*/
|
||||
int mac80211_connect(const char *interface, void **nl_sock, int *nl80211_id,
|
||||
int *if_index, char *errstr);
|
||||
|
||||
/* Disconnect from nl80211; frees resources used */
|
||||
void mac80211_disconnect(void *nl_sock);
|
||||
|
||||
/* Set a channel on an interface via mac80211, initiating a new connection
|
||||
* to the interface.
|
||||
*
|
||||
* Generally, it's better to use mac80211_set_channel_cache which re-uses the
|
||||
* connected state instead of opening a new mac80211 socket every channel config.
|
||||
*
|
||||
* Channel must be base frequency or channel number. Mode must be one of
|
||||
* nl80211_channel_type from nl80211.h. For setting 80, 160, or 80+80 channels, use
|
||||
* mac80211_set_freq
|
||||
*
|
||||
* errstr must be allocated by the caller and be able to hold STATUS_MAX
|
||||
* characters.
|
||||
*
|
||||
* Returns:
|
||||
* -1 Error
|
||||
* 0 Success
|
||||
*/
|
||||
int mac80211_set_channel(const char *interface, int channel, unsigned int chmode, char *errstr);
|
||||
int mac80211_set_channel_cache(int ifindex, void *nl_sock, int nl80211_id,
|
||||
int channel, unsigned int chmode, char *errstr);
|
||||
|
||||
/* Set a device frequency by frequency, width, and center frequency, required for
|
||||
* advanced 11AC controls. This MAY also be used for 11n 40mhz channels.
|
||||
*
|
||||
* Generally, it's best to use mac80211_set_frequency_cache(...) which re-uses the
|
||||
* connected state from mac80211_open.
|
||||
*
|
||||
* chan_width must be one of nl80211_chan_width from nl80211.h
|
||||
*
|
||||
* errstr must be allocated by the caller and be able to hold STATUS_MAX characters.
|
||||
*
|
||||
* Returns:
|
||||
* -1 Error
|
||||
* 0 Success
|
||||
*
|
||||
*/
|
||||
int mac80211_set_frequency(const char *interface, unsigned int control_freq,
|
||||
unsigned int chan_width, unsigned int center_freq1, unsigned int center_freq2,
|
||||
char *errstr);
|
||||
int mac80211_set_frequency_cache(int ifidx, void *nl_sock, int nl80211_id,
|
||||
unsigned int control_freq, unsigned int chan_width, unsigned int center_freq1,
|
||||
unsigned int center_freq2, char *errstr);
|
||||
|
||||
/* Get the parent phy of an interface.
|
||||
*
|
||||
* Returns:
|
||||
* NULL Error
|
||||
* ptr Pointer to dynamically allocated string containing the parent; the caller
|
||||
* is responsible for freeing this string.
|
||||
*/
|
||||
char *mac80211_find_parent(const char *interface);
|
||||
|
||||
#define MAC80211_CHANLIST_NO_INTERFACE -2
|
||||
#define MAC80211_CHANLIST_NOT_MAC80211 -3
|
||||
#define MAC80211_CHANLIST_GENERIC -4
|
||||
|
||||
#define MAC80211_GET_HT (1 << 0)
|
||||
#define MAC80211_GET_VHT (1 << 1)
|
||||
|
||||
/* Get a complete channel list supported by an interface.
|
||||
*
|
||||
* This extracts any information about HT40, 80, and 160 from the device specs,
|
||||
* and combines it with the pre-defined knowledge about 802.11 channel allocation
|
||||
* to compute every channel permutation the interface should support.
|
||||
*
|
||||
* Channels are returned as Kismet channel definitions, as wifi channel strings; for
|
||||
* example:
|
||||
* Base channel: 6
|
||||
* HT20 channel: 6HT20
|
||||
* HT40+ channel: 6HT40+
|
||||
* HT40- channel: 6HT40-
|
||||
* HT80 channel: 36HT80 (which automatically derives 80mhz control channel)
|
||||
* HT160 channel: 36HT160 (which automatically derives 160mhz control channel)
|
||||
*
|
||||
* Returns channel list array in *ret_chanlist and length in *ret_chanlist_len.
|
||||
*
|
||||
* Caller is responsible for freeing returned chanlist with mac80211_free_chanlist(..)
|
||||
*
|
||||
* If default_ht20 is true, then for any interface capable of ht20, all
|
||||
* 20mhz channels will be returned as ht20 channels. expand_ht20 will be
|
||||
* ignored.
|
||||
*
|
||||
* If expand_ht20 is true (and default_ht20 is false), then for any interface
|
||||
* capable of ht20, all 20mhz channels will be reported as both non-ht and ht20
|
||||
* in the returned list.
|
||||
*
|
||||
* Returns:
|
||||
* -1 Error
|
||||
* 0 Success
|
||||
*
|
||||
*/
|
||||
int mac80211_get_chanlist(const char *interface, unsigned int extended_flags, char *errstr,
|
||||
unsigned int default_ht20, unsigned int expand_ht20,
|
||||
char ***ret_chanlist, size_t *ret_chanlist_len);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,183 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* Control the Nexmon drivers
|
||||
*
|
||||
* Definitions and control methods from the libnexio code in the
|
||||
* nexmon project
|
||||
*/
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "linux_nexmon_control.h"
|
||||
|
||||
#define NETLINK_USER 31
|
||||
|
||||
struct nexmon_t *init_nexmon(const char *ifname) {
|
||||
struct nexmon_t *nmon = (struct nexmon_t *) malloc(sizeof(struct nexmon_t));
|
||||
|
||||
int err = 0;
|
||||
struct sockaddr_nl *snl_tx = (struct sockaddr_nl *) malloc(sizeof(struct sockaddr_nl));
|
||||
struct sockaddr_nl *snl_rx_ioctl = (struct sockaddr_nl *) malloc(sizeof(struct sockaddr_nl));
|
||||
struct timeval tv;
|
||||
|
||||
memset(snl_tx, 0, sizeof(struct sockaddr_nl));
|
||||
memset(snl_rx_ioctl, 0, sizeof(struct sockaddr_nl));
|
||||
|
||||
snl_tx->nl_family = AF_NETLINK;
|
||||
snl_tx->nl_pid = 0;
|
||||
snl_tx->nl_groups = 0;
|
||||
|
||||
snl_rx_ioctl->nl_family = AF_NETLINK;
|
||||
snl_rx_ioctl->nl_pid = getpid();
|
||||
|
||||
nmon->sock_tx = socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
|
||||
if (nmon->sock_tx < 0) {
|
||||
free(nmon);
|
||||
free(snl_tx);
|
||||
free(snl_rx_ioctl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nmon->sock_rx_ioctl = socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
|
||||
if (nmon->sock_rx_ioctl < 0) {
|
||||
close(nmon->sock_tx);
|
||||
free(nmon);
|
||||
free(snl_tx);
|
||||
free(snl_rx_ioctl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
setsockopt(nmon->sock_rx_ioctl, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
||||
|
||||
err = bind(nmon->sock_rx_ioctl, (struct sockaddr *) snl_rx_ioctl, sizeof(struct sockaddr));
|
||||
if (err) {
|
||||
close(nmon->sock_tx);
|
||||
close(nmon->sock_rx_ioctl);
|
||||
free(nmon);
|
||||
free(snl_tx);
|
||||
free(snl_rx_ioctl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = connect(nmon->sock_tx, (struct sockaddr *) snl_tx, sizeof(struct sockaddr));
|
||||
if (err) {
|
||||
close(nmon->sock_tx);
|
||||
close(nmon->sock_rx_ioctl);
|
||||
free(nmon);
|
||||
free(snl_tx);
|
||||
free(snl_rx_ioctl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return nmon;
|
||||
}
|
||||
|
||||
struct nex_ioctl {
|
||||
unsigned int cmd; /* common ioctl definition */
|
||||
void *buf; /* pointer to user buffer */
|
||||
unsigned int len; /* length of user buffer */
|
||||
bool set; /* get or set request (optional) */
|
||||
unsigned int used; /* bytes read or written (optional) */
|
||||
unsigned int needed; /* bytes needed (optional) */
|
||||
unsigned int driver; /* to identify target driver */
|
||||
};
|
||||
|
||||
struct nexudp_header {
|
||||
char nex[3];
|
||||
char type;
|
||||
int securitycookie;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct nexudp_ioctl_header {
|
||||
struct nexudp_header nexudphdr;
|
||||
unsigned int cmd;
|
||||
unsigned int set;
|
||||
char payload[1];
|
||||
} __attribute__((packed));
|
||||
|
||||
#define NEXUDP_IOCTL 0
|
||||
#define WLC_SET_MONITOR 108
|
||||
#define WLC_IOCTL_MAGIC 0x14e46c77
|
||||
|
||||
int nexmon_monitor(struct nexmon_t *nmon) {
|
||||
struct nex_ioctl ioc;
|
||||
uint32_t monitor_value = 2;
|
||||
int ret = 0;
|
||||
|
||||
ioc.cmd = WLC_SET_MONITOR;
|
||||
ioc.buf = &monitor_value;
|
||||
ioc.len = 4;
|
||||
ioc.set = true;
|
||||
ioc.driver = WLC_IOCTL_MAGIC;
|
||||
|
||||
int frame_len = ioc.len + sizeof(struct nexudp_ioctl_header) - sizeof(char);
|
||||
int rx_frame_len = 0;
|
||||
struct nexudp_ioctl_header *frame;
|
||||
|
||||
struct nlmsghdr *nlh = (struct nlmsghdr *) malloc(NLMSG_SPACE(frame_len));
|
||||
memset(nlh, 0, NLMSG_SPACE(frame_len));
|
||||
nlh->nlmsg_len = NLMSG_SPACE(frame_len);
|
||||
nlh->nlmsg_pid = getpid();
|
||||
nlh->nlmsg_flags = 0;
|
||||
frame = (struct nexudp_ioctl_header *) NLMSG_DATA(nlh);
|
||||
|
||||
memcpy(&frame->nexudphdr.nex, "NEX", 3);
|
||||
frame->nexudphdr.type = NEXUDP_IOCTL;
|
||||
frame->nexudphdr.securitycookie = nmon->securitycookie;
|
||||
|
||||
frame->cmd = ioc.cmd;
|
||||
frame->set = ioc.set;
|
||||
|
||||
memcpy(frame->payload, ioc.buf, ioc.len);
|
||||
|
||||
send(nmon->sock_tx, nlh, nlh->nlmsg_len, 0);
|
||||
|
||||
rx_frame_len = recv(nmon->sock_rx_ioctl, nlh, nlh->nlmsg_len, 0);
|
||||
|
||||
free(nlh);
|
||||
|
||||
if (rx_frame_len < 0) {
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* Control the Nexmon drivers
|
||||
*
|
||||
* Definitions and control methods from the libnexio code in the
|
||||
* nexmon project
|
||||
*/
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#ifndef __LINUX_NEXMON_CONTROL_H__
|
||||
#define __LINUX_NEXMON_CONTROL_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <net/if.h>
|
||||
|
||||
struct nexmon_t {
|
||||
int sock_rx_ioctl;
|
||||
int sock_rx_frame;
|
||||
int sock_tx;
|
||||
int securitycookie;
|
||||
};
|
||||
|
||||
struct nexmon_t *init_nexmon(const char *ifname);
|
||||
int nexmon_monitor(struct nexmon_t *nmon);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,722 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#ifdef SYS_LINUX
|
||||
#include <net/if_arp.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/if_ether.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#ifdef HAVE_LINUX_WIRELESS
|
||||
#include <asm/types.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/wireless.h>
|
||||
|
||||
#ifndef rintf
|
||||
#define rintf(x) (float) rint((double) (x))
|
||||
#endif
|
||||
|
||||
#include "linux_wireless_control.h"
|
||||
|
||||
/* Internal freq conversions */
|
||||
float IwFreq2Float(struct iwreq *inreq) {
|
||||
return ((float) inreq->u.freq.m) * pow(10,inreq->u.freq.e);
|
||||
}
|
||||
|
||||
void IwFloat2Freq(double in_val, struct iw_freq *out_freq) {
|
||||
if (in_val <= 165) {
|
||||
out_freq->m = (uint32_t) in_val;
|
||||
out_freq->e = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
out_freq->e = (short) (floor(log10(in_val)));
|
||||
if(out_freq->e > 8) {
|
||||
out_freq->m = ((long) (floor(in_val / pow(10,out_freq->e - 6)))) * 100;
|
||||
out_freq->e -= 8;
|
||||
}
|
||||
else {
|
||||
out_freq->m = (uint32_t) in_val;
|
||||
out_freq->e = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int FloatChan2Int(float in_chan) {
|
||||
if (in_chan > 0 && in_chan < 165)
|
||||
return (int) in_chan;
|
||||
|
||||
int mod_chan = (int) rintf(in_chan / 1000000);
|
||||
int x = 0;
|
||||
// 80211b frequencies to channels
|
||||
int IEEE80211Freq[] = {
|
||||
2412, 2417, 2422, 2427, 2432,
|
||||
2437, 2442, 2447, 2452, 2457,
|
||||
2462, 2467, 2472, 2484,
|
||||
5180, 5200, 5210, 5220, 5240,
|
||||
5250, 5260, 5280, 5290, 5300,
|
||||
5320, 5745, 5760, 5765, 5785,
|
||||
5800, 5805, 5825,
|
||||
-1
|
||||
};
|
||||
|
||||
int IEEE80211Ch[] = {
|
||||
1, 2, 3, 4, 5,
|
||||
6, 7, 8, 9, 10,
|
||||
11, 12, 13, 14,
|
||||
36, 40, 42, 44, 48,
|
||||
50, 52, 56, 58, 60,
|
||||
64, 149, 152, 153, 157,
|
||||
160, 161, 165
|
||||
};
|
||||
|
||||
while (IEEE80211Freq[x] != -1) {
|
||||
if (IEEE80211Freq[x] == mod_chan) {
|
||||
return IEEE80211Ch[x];
|
||||
}
|
||||
x++;
|
||||
}
|
||||
|
||||
return mod_chan;
|
||||
}
|
||||
|
||||
|
||||
/* Code based largely on iwconfig tools code */
|
||||
int iwconfig_set_intpriv(const char *in_dev, const char *privcmd,
|
||||
int val1, int val2, char *errstr) {
|
||||
struct iwreq wrq;
|
||||
int skfd;
|
||||
struct iw_priv_args priv[IW_MAX_PRIV_DEF];
|
||||
u_char buffer[4096];
|
||||
__s32 *sbuffer = (__s32 *) buffer;
|
||||
int subcmd = 0;
|
||||
int offset = 0;
|
||||
|
||||
memset(priv, 0, sizeof(priv));
|
||||
|
||||
if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"failed to connect to interface '%s' to set private ioctl: %s",
|
||||
in_dev, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&wrq, 0, sizeof(struct iwreq));
|
||||
strncpy(wrq.ifr_name, in_dev, IFNAMSIZ);
|
||||
|
||||
wrq.u.data.pointer = (caddr_t) priv;
|
||||
wrq.u.data.length = IW_MAX_PRIV_DEF;
|
||||
wrq.u.data.flags = 0;
|
||||
|
||||
if (ioctl(skfd, SIOCGIWPRIV, &wrq) < 0) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"failed to get list of supported ioctls on interface '%s': %s",
|
||||
in_dev, strerror(errno));
|
||||
close(skfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pn = -1;
|
||||
while ((++pn < wrq.u.data.length) && strcmp(priv[pn].name, privcmd));
|
||||
|
||||
if (pn == wrq.u.data.length) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"failed to find private ioctl command '%s' on interface '%s'",
|
||||
privcmd, in_dev);
|
||||
close(skfd);
|
||||
return -2;
|
||||
}
|
||||
|
||||
// Find subcmds, as if this isn't ugly enough already
|
||||
if (priv[pn].cmd < SIOCDEVPRIVATE) {
|
||||
int j = -1;
|
||||
|
||||
while ((++j < wrq.u.data.length) &&
|
||||
((priv[j].name[0] != '\0') || (priv[j].set_args != priv[pn].set_args) ||
|
||||
(priv[j].get_args != priv[pn].get_args)));
|
||||
|
||||
if (j == wrq.u.data.length) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"failed to find sub-command '%s' on interface '%s'",
|
||||
privcmd, in_dev);
|
||||
close(skfd);
|
||||
return -2;
|
||||
}
|
||||
|
||||
subcmd = priv[pn].cmd;
|
||||
offset = sizeof(__u32);
|
||||
pn = j;
|
||||
}
|
||||
|
||||
// Make sure its an iwpriv we can set
|
||||
if ((priv[pn].set_args & IW_PRIV_TYPE_MASK) == 0 ||
|
||||
(priv[pn].set_args & IW_PRIV_SIZE_MASK) == 0) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"unable to set values for private ioctl '%s' on interface '%s'",
|
||||
privcmd, in_dev);
|
||||
close(skfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((priv[pn].set_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"private ioctl '%s' on interface '%s' does not accept integer "
|
||||
"parameters.", privcmd, in_dev);
|
||||
close(skfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Find out how many arguments it takes and die if we can't handle it
|
||||
int nargs = (priv[pn].set_args & IW_PRIV_SIZE_MASK);
|
||||
if (nargs > 2) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"private ioctl '%s' on interface '%s' expects more than "
|
||||
"2 arguments.", privcmd, in_dev);
|
||||
close(skfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Build the set request
|
||||
memset(&wrq, 0, sizeof(struct iwreq));
|
||||
strncpy(wrq.ifr_name, in_dev, IFNAMSIZ);
|
||||
|
||||
// Assign the arguments
|
||||
wrq.u.data.length = nargs;
|
||||
sbuffer[0] = (__s32) val1;
|
||||
if (nargs > 1) {
|
||||
sbuffer[1] = (__s32) val2;
|
||||
}
|
||||
|
||||
// This is terrible!
|
||||
// This is also simplified from what iwpriv.c does, because we don't
|
||||
// need to worry about get-no-set ioctls
|
||||
if ((priv[pn].set_args & IW_PRIV_SIZE_FIXED) &&
|
||||
((sizeof(__u32) * nargs) + offset <= IFNAMSIZ)) {
|
||||
if (offset)
|
||||
wrq.u.mode = subcmd;
|
||||
memcpy(wrq.u.name + offset, buffer, IFNAMSIZ - offset);
|
||||
} else {
|
||||
wrq.u.data.pointer = (caddr_t) buffer;
|
||||
wrq.u.data.flags = 0;
|
||||
}
|
||||
|
||||
// Actually do it.
|
||||
if (ioctl(skfd, priv[pn].cmd, &wrq) < 0) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"failed to set private ioctl '%s' on interface '%s': %s",
|
||||
privcmd, in_dev, strerror(errno));
|
||||
close(skfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(skfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iwconfig_get_intpriv(const char *in_dev, const char *privcmd,
|
||||
int *val, char *errstr) {
|
||||
struct iwreq wrq;
|
||||
int skfd;
|
||||
struct iw_priv_args priv[IW_MAX_PRIV_DEF];
|
||||
u_char buffer[4096];
|
||||
__s32 *sbuffer = (__s32 *) buffer;
|
||||
int subcmd = 0;
|
||||
int offset = 0;
|
||||
|
||||
memset(priv, 0, sizeof(priv));
|
||||
|
||||
if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"failed to connect to interface '%s' to fetch private ioctl: %s",
|
||||
in_dev, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&wrq, 0, sizeof(struct iwreq));
|
||||
strncpy(wrq.ifr_name, in_dev, IFNAMSIZ);
|
||||
|
||||
wrq.u.data.pointer = (caddr_t) priv;
|
||||
wrq.u.data.length = IW_MAX_PRIV_DEF;
|
||||
wrq.u.data.flags = 0;
|
||||
|
||||
if (ioctl(skfd, SIOCGIWPRIV, &wrq) < 0) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"failed to retrieve list of private ioctls on interface '%s': %s",
|
||||
in_dev, strerror(errno));
|
||||
close(skfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pn = -1;
|
||||
while ((++pn < wrq.u.data.length) && strcmp(priv[pn].name, privcmd));
|
||||
|
||||
if (pn == wrq.u.data.length) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"failed to find private ioctl '%s' on interface '%s'",
|
||||
privcmd, in_dev);
|
||||
close(skfd);
|
||||
return -2;
|
||||
}
|
||||
|
||||
// Find subcmds, as if this isn't ugly enough already
|
||||
if (priv[pn].cmd < SIOCDEVPRIVATE) {
|
||||
int j = -1;
|
||||
|
||||
while ((++j < wrq.u.data.length) && ((priv[j].name[0] != '\0') ||
|
||||
(priv[j].set_args != priv[pn].set_args) ||
|
||||
(priv[j].get_args != priv[pn].get_args)));
|
||||
|
||||
if (j == wrq.u.data.length) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"unable to find subioctl '%s' on interface '%s'",
|
||||
privcmd, in_dev);
|
||||
close(skfd);
|
||||
return -2;
|
||||
}
|
||||
|
||||
subcmd = priv[pn].cmd;
|
||||
offset = sizeof(__u32);
|
||||
pn = j;
|
||||
}
|
||||
|
||||
// Make sure its an iwpriv we can set
|
||||
if ((priv[pn].get_args & IW_PRIV_TYPE_MASK) == 0 ||
|
||||
(priv[pn].get_args & IW_PRIV_SIZE_MASK) == 0) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"unable to get values for private ioctl '%s' on interface '%s'",
|
||||
privcmd, in_dev);
|
||||
close(skfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((priv[pn].get_args & IW_PRIV_TYPE_MASK) != IW_PRIV_TYPE_INT) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"private ioctl '%s' on interface '%s' does not return "
|
||||
"integer parameters.", privcmd, in_dev);
|
||||
close(skfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Find out how many arguments it takes and die if we can't handle it
|
||||
int nargs = (priv[pn].get_args & IW_PRIV_SIZE_MASK);
|
||||
if (nargs > 1) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"private ioctl '%s' on interface '%s' returns more than 1 "
|
||||
"parameter and we can't handle that at the moment.", privcmd, in_dev);
|
||||
close(skfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Build the get request
|
||||
memset(&wrq, 0, sizeof(struct iwreq));
|
||||
strncpy(wrq.ifr_name, in_dev, IFNAMSIZ);
|
||||
|
||||
// Assign the arguments
|
||||
wrq.u.data.length = 0L;
|
||||
|
||||
// This is terrible!
|
||||
// Simplified (again) from iwpriv, since we split the command into
|
||||
// a set and a get instead of combining the cases
|
||||
if ((priv[pn].get_args & IW_PRIV_SIZE_FIXED) &&
|
||||
((sizeof(__u32) * nargs) + offset <= IFNAMSIZ)) {
|
||||
/* Second case : no SET args, GET args fit within wrq */
|
||||
if (offset)
|
||||
wrq.u.mode = subcmd;
|
||||
} else {
|
||||
wrq.u.data.pointer = (caddr_t) buffer;
|
||||
wrq.u.data.flags = 0;
|
||||
}
|
||||
|
||||
// Actually do it.
|
||||
if (ioctl(skfd, priv[pn].cmd, &wrq) < 0) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"failed to call get private ioctl '%s' on interface '%s': %s",
|
||||
privcmd, in_dev, strerror(errno));
|
||||
close(skfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Where do we get the data from?
|
||||
if ((priv[pn].get_args & IW_PRIV_SIZE_FIXED) &&
|
||||
((sizeof(__u32) * nargs) + offset <= IFNAMSIZ))
|
||||
memcpy(buffer, wrq.u.name, IFNAMSIZ);
|
||||
|
||||
// Return the value of the ioctl
|
||||
(*val) = sbuffer[0];
|
||||
|
||||
close(skfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iwconfig_get_channel(const char *in_dev, char *in_err) {
|
||||
struct iwreq wrq;
|
||||
int skfd;
|
||||
|
||||
if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
snprintf(in_err, STATUS_MAX,
|
||||
"failed to connect to interface '%s' to get channel: %s",
|
||||
in_dev, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&wrq, 0, sizeof(struct iwreq));
|
||||
strncpy(wrq.ifr_name, in_dev, IFNAMSIZ);
|
||||
|
||||
if (ioctl(skfd, SIOCGIWFREQ, &wrq) < 0) {
|
||||
snprintf(in_err, STATUS_MAX,
|
||||
"failed to get channel from interface '%s': %s",
|
||||
in_dev, strerror(errno));
|
||||
close(skfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(skfd);
|
||||
return (FloatChan2Int(IwFreq2Float(&wrq)));
|
||||
}
|
||||
|
||||
int iwconfig_set_channel(const char *in_dev, int in_ch, char *in_err) {
|
||||
struct iwreq wrq;
|
||||
int skfd;
|
||||
int ret = 0;
|
||||
|
||||
if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
snprintf(in_err, STATUS_MAX,
|
||||
"failed to connect to interface '%s' to set channel: %s",
|
||||
in_dev, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
// Set a channel
|
||||
memset(&wrq, 0, sizeof(struct iwreq));
|
||||
|
||||
strncpy(wrq.ifr_name, in_dev, IFNAMSIZ);
|
||||
#ifdef HAVE_LINUX_IWFREQFLAG
|
||||
wrq.u.freq.flags = IW_FREQ_FIXED;
|
||||
#endif
|
||||
if (in_ch > 1024)
|
||||
IwFloat2Freq(in_ch * 1e6, &wrq.u.freq);
|
||||
else
|
||||
IwFloat2Freq(in_ch, &wrq.u.freq);
|
||||
|
||||
/* Try twice with a tiny delay, some cards (madwifi) need a second chance... */
|
||||
if (ioctl(skfd, SIOCSIWFREQ, &wrq) < 0) {
|
||||
struct timeval tm;
|
||||
tm.tv_sec = 0;
|
||||
tm.tv_usec = 5000;
|
||||
select(0, NULL, NULL, NULL, &tm);
|
||||
|
||||
if (ioctl(skfd, SIOCSIWFREQ, &wrq) < 0) {
|
||||
if (errno == ENODEV) {
|
||||
ret = -2;
|
||||
} else {
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
snprintf(in_err, STATUS_MAX,
|
||||
"unable to set channel on interface '%s': %s",
|
||||
in_dev, strerror(errno));
|
||||
|
||||
close(skfd);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
close(skfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iwconfig_get_mode(const char *in_dev, char *in_err, int *in_mode) {
|
||||
struct iwreq wrq;
|
||||
int skfd;
|
||||
|
||||
if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
snprintf(in_err, STATUS_MAX,
|
||||
"failed to connect to interface '%s' to set mode: %s",
|
||||
in_dev, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&wrq, 0, sizeof(struct iwreq));
|
||||
strncpy(wrq.ifr_name, in_dev, IFNAMSIZ);
|
||||
|
||||
if (ioctl(skfd, SIOCGIWMODE, &wrq) < 0) {
|
||||
snprintf(in_err, STATUS_MAX,
|
||||
"failed to get mode from interface '%s': %s",
|
||||
in_dev, strerror(errno));
|
||||
close(skfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
(*in_mode) = wrq.u.mode;
|
||||
|
||||
close(skfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iwconfig_set_mode(const char *in_dev, char *in_err, int in_mode) {
|
||||
struct iwreq wrq;
|
||||
int skfd;
|
||||
|
||||
if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
snprintf(in_err, STATUS_MAX,
|
||||
"failed to connect to interface '%s' to set mode: %s",
|
||||
in_dev, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&wrq, 0, sizeof(struct iwreq));
|
||||
strncpy(wrq.ifr_name, in_dev, IFNAMSIZ);
|
||||
wrq.u.mode = in_mode;
|
||||
|
||||
if (ioctl(skfd, SIOCSIWMODE, &wrq) < 0) {
|
||||
snprintf(in_err, STATUS_MAX, "failed to set mode on interface '%s': %s",
|
||||
in_dev, strerror(errno));
|
||||
close(skfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(skfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* straight from wireless-tools; range struct definitions */
|
||||
#define IW15_MAX_FREQUENCIES 16
|
||||
#define IW15_MAX_BITRATES 8
|
||||
#define IW15_MAX_TXPOWER 8
|
||||
#define IW15_MAX_ENCODING_SIZES 8
|
||||
#define IW15_MAX_SPY 8
|
||||
#define IW15_MAX_AP 8
|
||||
struct iw15_range {
|
||||
uint32_t throughput;
|
||||
uint32_t min_nwid;
|
||||
uint32_t max_nwid;
|
||||
uint16_t num_channels;
|
||||
uint8_t num_frequency;
|
||||
struct iw_freq freq[IW15_MAX_FREQUENCIES];
|
||||
int32_t sensitivity;
|
||||
struct iw_quality max_qual;
|
||||
uint8_t num_bitrates;
|
||||
int32_t bitrate[IW15_MAX_BITRATES];
|
||||
int32_t min_rts;
|
||||
int32_t max_rts;
|
||||
int32_t min_frag;
|
||||
int32_t max_frag;
|
||||
int32_t min_pmp;
|
||||
int32_t max_pmp;
|
||||
int32_t min_pmt;
|
||||
int32_t max_pmt;
|
||||
uint16_t pmp_flags;
|
||||
uint16_t pmt_flags;
|
||||
uint16_t pm_capa;
|
||||
uint16_t encoding_size[IW15_MAX_ENCODING_SIZES];
|
||||
uint8_t num_encoding_sizes;
|
||||
uint8_t max_encoding_tokens;
|
||||
uint16_t txpower_capa;
|
||||
uint8_t num_txpower;
|
||||
int32_t txpower[IW15_MAX_TXPOWER];
|
||||
uint8_t we_version_compiled;
|
||||
uint8_t we_version_source;
|
||||
uint16_t retry_capa;
|
||||
uint16_t retry_flags;
|
||||
uint16_t r_time_flags;
|
||||
int32_t min_retry;
|
||||
int32_t max_retry;
|
||||
int32_t min_r_time;
|
||||
int32_t max_r_time;
|
||||
struct iw_quality avg_qual;
|
||||
};
|
||||
|
||||
union iw_range_raw {
|
||||
struct iw15_range range15; /* WE 9->15 */
|
||||
struct iw_range range; /* WE 16->current */
|
||||
};
|
||||
|
||||
/*
|
||||
* Offsets in iw_range struct
|
||||
*/
|
||||
#define iwr15_off(f) ( ((char *) &(((struct iw15_range *) NULL)->f)) - \
|
||||
(char *) NULL)
|
||||
#define iwr_off(f) ( ((char *) &(((struct iw_range *) NULL)->f)) - \
|
||||
(char *) NULL)
|
||||
|
||||
/* Get hw supported channels; rewritten from wireless-tools by Jean Tourilhes */
|
||||
int iwconfig_get_chanlist(const char *interface, char *errstr,
|
||||
unsigned int **chan_list, size_t *chan_list_len) {
|
||||
struct iwreq wrq;
|
||||
int skfd;
|
||||
char buffer[sizeof(struct iw_range) * 2];
|
||||
union iw_range_raw *range_raw;
|
||||
struct iw_range range;
|
||||
int k;
|
||||
|
||||
*chan_list = NULL;
|
||||
*chan_list_len = 0;
|
||||
|
||||
if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"failed to connect to interface '%s' to get channel list: %s",
|
||||
interface, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
|
||||
memset(&wrq, 0, sizeof(struct iwreq));
|
||||
|
||||
wrq.u.data.pointer = (caddr_t) buffer;
|
||||
wrq.u.data.length = sizeof(buffer);
|
||||
wrq.u.data.flags = 0;
|
||||
|
||||
strncpy(wrq.ifr_name, interface, IFNAMSIZ);
|
||||
|
||||
if (ioctl(skfd, SIOCGIWRANGE, &wrq) < 0) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"failed to get channel list from interface '%s': %s",
|
||||
interface, strerror(errno));
|
||||
close(skfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
range_raw = (union iw_range_raw *) buffer;
|
||||
|
||||
/* Magic number to detect old versions */
|
||||
/* For new versions, we can check the version directly, for old versions
|
||||
* we use magic. 300 bytes is a also magic number, don't touch... */
|
||||
if (wrq.u.data.length < 300) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"failed to get channel list from interface '%s': its drivers "
|
||||
"are too old to support fetching the supported channels.",
|
||||
interface);
|
||||
close(skfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Direct copy from wireless-tools; mangle the range code and
|
||||
* figure out what we need to do with it */
|
||||
if (range_raw->range.we_version_compiled > 15) {
|
||||
memcpy((char *) &range, buffer, sizeof(struct iw_range));
|
||||
} else {
|
||||
/* Zero unknown fields */
|
||||
memset((char *) &range, 0, sizeof(struct iw_range));
|
||||
|
||||
/* Initial part unmoved */
|
||||
memcpy((char *) &range, buffer, iwr15_off(num_channels));
|
||||
/* Frequencies pushed further down towards the end */
|
||||
memcpy((char *) &range + iwr_off(num_channels),
|
||||
buffer + iwr15_off(num_channels),
|
||||
iwr15_off(sensitivity) - iwr15_off(num_channels));
|
||||
/* This one moved up */
|
||||
memcpy((char *) &range + iwr_off(sensitivity),
|
||||
buffer + iwr15_off(sensitivity),
|
||||
iwr15_off(num_bitrates) - iwr15_off(sensitivity));
|
||||
/* This one goes after avg_qual */
|
||||
memcpy((char *) &range + iwr_off(num_bitrates),
|
||||
buffer + iwr15_off(num_bitrates),
|
||||
iwr15_off(min_rts) - iwr15_off(num_bitrates));
|
||||
/* Number of bitrates has changed, put it after */
|
||||
memcpy((char *) &range + iwr_off(min_rts),
|
||||
buffer + iwr15_off(min_rts),
|
||||
iwr15_off(txpower_capa) - iwr15_off(min_rts));
|
||||
/* Added encoding_login_index, put it after */
|
||||
memcpy((char *) &range + iwr_off(txpower_capa),
|
||||
buffer + iwr15_off(txpower_capa),
|
||||
iwr15_off(txpower) - iwr15_off(txpower_capa));
|
||||
/* Hum... That's an unexpected glitch. Bummer. */
|
||||
memcpy((char *) &range + iwr_off(txpower),
|
||||
buffer + iwr15_off(txpower),
|
||||
iwr15_off(avg_qual) - iwr15_off(txpower));
|
||||
/* Avg qual moved up next to max_qual */
|
||||
memcpy((char *) &range + iwr_off(avg_qual),
|
||||
buffer + iwr15_off(avg_qual),
|
||||
sizeof(struct iw_quality));
|
||||
}
|
||||
|
||||
if (range.we_version_compiled <= 10) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"failed to get channel list from interface '%s': its drivers "
|
||||
"are too old to support fetching the supported channels.",
|
||||
interface);
|
||||
close(skfd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* We don't actually care?
|
||||
if (range.we_version_compiled > WE_MAX_VERSION) {
|
||||
snprintf(errstr, STATUS_MAX, "Interface %s using wireless extensions from "
|
||||
"the future; Recompile Kismet with your new kernel before Skynet "
|
||||
"takes over", interface);
|
||||
close(skfd);
|
||||
return -1;
|
||||
}
|
||||
*/
|
||||
|
||||
if (range.num_frequency <= 0) {
|
||||
*chan_list = NULL;
|
||||
*chan_list_len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*chan_list = (unsigned int *) malloc(sizeof(unsigned int) * range.num_frequency);
|
||||
*chan_list_len = range.num_frequency;
|
||||
|
||||
if (*chan_list == NULL) {
|
||||
snprintf(errstr, STATUS_MAX,
|
||||
"failed to get channel list from interface '%s': insufficient memory "
|
||||
"to allocate channel list.", interface);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (k = 0; k < range.num_frequency; k++) {
|
||||
int freq = (((double) range.freq[k].m) * pow(10, range.freq[k].e)) /
|
||||
1000000;
|
||||
|
||||
(*chan_list)[k] = freq;
|
||||
}
|
||||
|
||||
close(skfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
int linux_sys_get_regdom(char *ret_countrycode) {
|
||||
FILE *regf;
|
||||
|
||||
if ((regf = fopen("/sys/module/cfg80211/parameters/ieee80211_regdom", "r")) == NULL)
|
||||
return -1;
|
||||
|
||||
if (fscanf(regf, "%4s", ret_countrycode) != 1) {
|
||||
fclose(regf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fclose(regf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // wireless
|
||||
|
|
@ -1,189 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __WIRELESS_CONTROL_H__
|
||||
#define __WIRELESS_CONTROL_H__
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef HAVE_LINUX_WIRELESS
|
||||
|
||||
#define IW_MAX_PRIV_DEF 256
|
||||
/* Wireless extentions monitor mode number */
|
||||
#define LINUX_WLEXT_MONITOR 6
|
||||
/* Wireless extentions master mode */
|
||||
#define LINUX_WLEXT_MASTER 3
|
||||
|
||||
/* Max version of wext we know about */
|
||||
#define WE_MAX_VERSION 22
|
||||
|
||||
/* Set a private ioctl that takes 1 or 2 integer parameters
|
||||
* A return of -2 means no privctl found that matches, so that the caller
|
||||
* can return a more detailed failure message
|
||||
*
|
||||
* This DOES NOT handle sub-ioctls. I've never seen them used. If this
|
||||
* blows up some day on some driver, I'll fix it.
|
||||
*
|
||||
* This uses the old-style wireless IOCTLs and should be supplanted by mac80211
|
||||
* for all modern drivers.
|
||||
*
|
||||
* errstr must be allocated by the caller and must be able to hold STATUS_MAX
|
||||
* characters.
|
||||
*
|
||||
* Returns:
|
||||
* -2 Unable to find IOCTL
|
||||
* -1 General error
|
||||
* 0 Success
|
||||
*/
|
||||
int iwconfig_set_intpriv(const char *in_dev, const char *privcmd,
|
||||
int val1, int val2, char *errstr);
|
||||
|
||||
/* Get a single-param private ioctl. This will have to be changed if we
|
||||
* ever need to remember a two-value privioctl, but hopefully nothing
|
||||
* will.
|
||||
*
|
||||
* This uses the old-style IOCTLs and should be supplanted by mac80211 for all
|
||||
* modern drivers.
|
||||
*
|
||||
* This does NOT handle sub-ioctls.
|
||||
*
|
||||
* errstr must be allocated by the caller and must be able to hold STATUS_MAX
|
||||
* characters.
|
||||
*
|
||||
* Returns:
|
||||
* -2 Unable to find private IOCTL
|
||||
* -1 General error
|
||||
* 0 Success
|
||||
*/
|
||||
int iwconfig_get_intpriv(const char *in_dev, const char *privcmd,
|
||||
int *val, char *errstr);
|
||||
|
||||
/* Get the current channel of a wireless device.
|
||||
*
|
||||
* This uses the old-style IOCTLs and should be supplanted by mac80211 for all
|
||||
* modern drivers.
|
||||
*
|
||||
* Because this uses the old-style controls, it cannot relay if the channel
|
||||
* has any HT or wide-tuning attributes, and returns a pure integer.
|
||||
*
|
||||
* errstr must be allocated by the caller and must be able to hold STATUS_MAX
|
||||
* characters.
|
||||
*
|
||||
* Returns:
|
||||
* -2 No device
|
||||
* -1 General error
|
||||
* othr Channel or frequency
|
||||
*/
|
||||
int iwconfig_get_channel(const char *in_dev, char *errstr);
|
||||
|
||||
/* Set the current channel of a wireless device.
|
||||
*
|
||||
* This uses the old-style IOCTLs and should be supplanted by mac80211 for all
|
||||
* modern drivers.
|
||||
*
|
||||
* Because this uses the old-style controls, it cannot configure a different
|
||||
* channel width or a wide
|
||||
*
|
||||
* errstr must be allocated by the caller and must be able to hold STATUS_MAX
|
||||
* characters.
|
||||
*
|
||||
* Returns:
|
||||
* -2 No device
|
||||
* -1 General error
|
||||
* 0 Success
|
||||
*/
|
||||
int iwconfig_set_channel(const char *in_dev, int in_ch, char *errstr);
|
||||
|
||||
/* Get the current mode of a wireless device (master, monitor, station, etc).
|
||||
*
|
||||
* This uses the old-style IOCTLs and should be supplanted by mac80211 for all
|
||||
* modern drivers.
|
||||
*
|
||||
* Modern drivers support getting mode, but cannot change the mode on an existing
|
||||
* interface.
|
||||
*
|
||||
* errstr must be allocated by the caller and must be able to hold STATUS_MAX
|
||||
* characters.
|
||||
*
|
||||
* Returns mode in in_mode
|
||||
*
|
||||
* Returns:
|
||||
* -1 Error
|
||||
* 0 Success
|
||||
*/
|
||||
int iwconfig_get_mode(const char *in_dev, char *errstr, int *in_mode);
|
||||
|
||||
|
||||
/* Set the current mode of a wireless device (master, monitor, station, etc).
|
||||
*
|
||||
* This uses the old-style IOCTLs and should be supplanted by mac80211 for all
|
||||
* modern drivers.
|
||||
*
|
||||
* Modern drivers support getting mode, but cannot change the mode on an existing
|
||||
* interface - a new vif must be created.
|
||||
*
|
||||
* errstr must be allocated by the caller and must be able to hold STATUS_MAX
|
||||
* characters.
|
||||
*
|
||||
* Returns:
|
||||
* -1 Error
|
||||
* 0 Success
|
||||
*/
|
||||
int iwconfig_set_mode(const char *in_dev, char *errstr, int in_mode);
|
||||
|
||||
/* Convert a channel floating value to an integer for formatting for old-style
|
||||
* IOCTLs */
|
||||
int floatchan_to_int(float in_chan);
|
||||
|
||||
/* Fetch a list of channels, as integers, from a wireless device.
|
||||
*
|
||||
* As this uses the old IOCTL model, it's not possible to fetch HT capable
|
||||
* data, so the channels are returned as a list of unsigned integers and must
|
||||
* be converted to proper Kismet format by the caller.
|
||||
*
|
||||
* Returns a list of integers in *chan_list and the length of the list in
|
||||
* *chan_list_len; Caller is responsible for freeing these objects.
|
||||
*
|
||||
* Returns:
|
||||
* -1 Error
|
||||
* 0 Success
|
||||
*/
|
||||
int iwconfig_get_chanlist(const char *interface, char *errstr,
|
||||
unsigned int **chan_list, size_t *chan_list_len);
|
||||
|
||||
#endif
|
||||
|
||||
/* Fetch the regulatory domain country code for the system
|
||||
*
|
||||
* This uses the /sys filesystem to query cfg80211 to see what the country code is
|
||||
* set to.
|
||||
*
|
||||
* *ret_countrycode must be allocated by the caller and be able to hold 4 bytes.
|
||||
*
|
||||
* Returns:
|
||||
* -1 Error, cannot get country code
|
||||
* 0 Success
|
||||
*/
|
||||
int linux_sys_get_regdom(char *ret_countrycode);
|
||||
|
||||
#endif
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "../config.h"
|
||||
#include "linux_wireless_rfkill.h"
|
||||
|
||||
#ifdef SYS_LINUX
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int linux_sys_get_rfkill(const char *interface, unsigned int rfkill_type) {
|
||||
DIR *devdir;
|
||||
struct dirent *devfile;
|
||||
char dirpath[2048];
|
||||
|
||||
const char *rfkill_key = "rfkill";
|
||||
const char *hard_key = "hard";
|
||||
const char *soft_key = "soft";
|
||||
|
||||
FILE *killf;
|
||||
|
||||
int r;
|
||||
|
||||
snprintf(dirpath, 2048, "/sys/class/net/%s/phy80211/", interface);
|
||||
|
||||
if ((devdir = opendir(dirpath)) == NULL)
|
||||
return -1;
|
||||
|
||||
while ((devfile = readdir(devdir)) != NULL) {
|
||||
if (strlen(devfile->d_name) < strlen(rfkill_key))
|
||||
continue;
|
||||
|
||||
if (strncmp(devfile->d_name, rfkill_key, strlen(rfkill_key)) == 0) {
|
||||
snprintf(dirpath, 2048, "/sys/class/net/%s/phy80211/%s/%s",
|
||||
interface, devfile->d_name,
|
||||
rfkill_type == 0 ? hard_key : soft_key);
|
||||
|
||||
if ((killf = fopen(dirpath, "r")) == NULL) {
|
||||
closedir(devdir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((fscanf(killf, "%d", &r)) != 1) {
|
||||
closedir(devdir);
|
||||
fclose(killf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
closedir(devdir);
|
||||
fclose(killf);
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int linux_sys_clear_rfkill(const char *interface) {
|
||||
DIR *devdir;
|
||||
struct dirent *devfile;
|
||||
char dirpath[2048];
|
||||
|
||||
const char *rfkill_key = "rfkill";
|
||||
|
||||
FILE *killf;
|
||||
|
||||
snprintf(dirpath, 2048, "/sys/class/net/%s/phy80211/", interface);
|
||||
|
||||
if ((devdir = opendir(dirpath)) == NULL)
|
||||
return -1;
|
||||
|
||||
while ((devfile = readdir(devdir)) != NULL) {
|
||||
if (strlen(devfile->d_name) < strlen(rfkill_key))
|
||||
continue;
|
||||
|
||||
if (strncmp(devfile->d_name, rfkill_key, strlen(rfkill_key)) == 0) {
|
||||
snprintf(dirpath, 2048, "/sys/class/net/%s/phy80211/%s/soft",
|
||||
interface, devfile->d_name);
|
||||
|
||||
if ((killf = fopen(dirpath, "w")) == NULL) {
|
||||
closedir(devdir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fprintf(killf, "%d\n", 0) < 0) {
|
||||
closedir(devdir);
|
||||
fclose(killf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
closedir(devdir);
|
||||
fclose(killf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_RFKILL_H__
|
||||
#define __LINUX_RFKILL_H__
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#ifdef HAVE_LINUX_WIRELESS
|
||||
|
||||
/* Fetch if rfkill is enabled on an interface
|
||||
*
|
||||
* This uses the /sys filesystem to query mac80211 drivers to see if the rfkill
|
||||
* attributes are enabled.
|
||||
*
|
||||
* rfkill_type == 0 checks hard kill
|
||||
* rfkill_type == 1 checks soft kill
|
||||
*
|
||||
* Returns:
|
||||
* -1 Error, cannot determine rfkill status
|
||||
* 0 Rfkill not enabled
|
||||
* 1 Rfkill enabled
|
||||
*/
|
||||
#define LINUX_RFKILL_TYPE_HARD 0
|
||||
#define LINUX_RFKILL_TYPE_SOFT 1
|
||||
int linux_sys_get_rfkill(const char *interface, unsigned int rfkill_type);
|
||||
|
||||
/* Disable soft rfkill on an interface
|
||||
*
|
||||
* This uses the /sys filesystem to query mac80211 drivers and clear the rfkill
|
||||
*
|
||||
* This only disables softkill as we cannot alter hard kill from sw
|
||||
*
|
||||
* Returns:
|
||||
* -1 Error, cannot change rfkill
|
||||
* 0 Success
|
||||
*/
|
||||
int linux_sys_clear_rfkill(const char *interface);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
include ../Makefile.inc
|
||||
|
||||
MONITOR_OBJS = \
|
||||
capture_nrf_mousejack.c.o
|
||||
MONITOR_BIN = kismet_cap_nrf_mousejack
|
||||
|
||||
all: $(MONITOR_BIN)
|
||||
|
||||
LIBUSBCFLAGS=@LIBUSBCFLAGS@
|
||||
LIBUSBLIBS=@LIBUSBLIBS@
|
||||
|
||||
$(MONITOR_BIN): $(MONITOR_OBJS) $(patsubst %c.o,%c.d,$(MONITOR_OBJS)) ../libkismetdatasource.a
|
||||
$(CCLD) $(LDFLAGS) -o $(MONITOR_BIN) $(MONITOR_OBJS) ../libkismetdatasource.a $(DATASOURCE_LIBS) $(LIBUSBLIBS)
|
||||
|
||||
clean:
|
||||
@-rm -f $(MONITOR_BIN)
|
||||
@-rm -f *.o
|
||||
@-rm -f *.d
|
||||
|
||||
%.c.o: %.c
|
||||
%.c.o : %.c %.c.d
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(LIBUSBCFLAGS) -c $*.c -o $@
|
||||
|
||||
%.c.d: %.c
|
||||
$(CC) -MM $(CFLAGS) $(CPPFLAGS) $*.c | sed -e "s/\.o/\.c.o/" > $*.c.d
|
||||
|
||||
.PRECIOUS: %.c.d
|
||||
|
||||
include $(wildcard $(patsubst %c.o,%c.d,$(MONITOR_OBJS)))
|
||||
|
|
@ -1,720 +0,0 @@
|
|||
/*
|
||||
Derived from the Bastille Mousejack python code.
|
||||
While Kismet is generally licensed under the GPL2 license, this binary is
|
||||
derived from GPL3 code from Bastille, and as such, is under that license.
|
||||
|
||||
Copyright (C) 2016 Bastille Networks
|
||||
Copyright (C) 2018 Mike Kershaw / dragorn@kismetwireless.net
|
||||
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#include "mousejack.h"
|
||||
|
||||
#include <libusb-1.0/libusb.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../capture_framework.h"
|
||||
|
||||
/* USB command timeout */
|
||||
#define NRF_USB_TIMEOUT 2500
|
||||
|
||||
/* Unique instance data passed around by capframework */
|
||||
typedef struct {
|
||||
libusb_context *libusb_ctx;
|
||||
libusb_device_handle *nrf_handle;
|
||||
|
||||
unsigned int devno, busno;
|
||||
|
||||
pthread_mutex_t usb_mutex;
|
||||
|
||||
/* we don't want to do a channel query every data response, we just want to
|
||||
* remember the last channel used */
|
||||
unsigned int channel;
|
||||
|
||||
kis_capture_handler_t *caph;
|
||||
} local_nrf_t;
|
||||
|
||||
/* Most basic of channel definitions */
|
||||
typedef struct {
|
||||
unsigned int channel;
|
||||
} local_channel_t;
|
||||
|
||||
int nrf_send_command_nb(kis_capture_handler_t *caph, uint8_t request, uint8_t *data, size_t len) {
|
||||
local_nrf_t *localnrf = (local_nrf_t *) caph->userdata;
|
||||
uint8_t *cmdbuf = NULL;
|
||||
int actual_length;
|
||||
int r;
|
||||
|
||||
cmdbuf = (uint8_t *) malloc(len + 1);
|
||||
cmdbuf[0] = request;
|
||||
|
||||
if (len > 0)
|
||||
memcpy(cmdbuf + 1, data, len);
|
||||
|
||||
r = libusb_bulk_transfer(localnrf->nrf_handle, MOUSEJACK_USB_ENDPOINT_OUT,
|
||||
cmdbuf, len + 1, &actual_length, NRF_USB_TIMEOUT);
|
||||
|
||||
free(cmdbuf);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int nrf_send_command(kis_capture_handler_t *caph, uint8_t request, uint8_t *data, size_t len) {
|
||||
local_nrf_t *localnrf = (local_nrf_t *) caph->userdata;
|
||||
int r;
|
||||
|
||||
pthread_mutex_lock(&(localnrf->usb_mutex));
|
||||
|
||||
r = nrf_send_command_nb(caph, request, data, len);
|
||||
|
||||
pthread_mutex_unlock(&(localnrf->usb_mutex));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int nrf_send_command_with_resp(kis_capture_handler_t *caph, uint8_t request, uint8_t *data,
|
||||
size_t len) {
|
||||
local_nrf_t *localnrf = (local_nrf_t *) caph->userdata;
|
||||
int r;
|
||||
unsigned char rx_buf[64];
|
||||
int actual_length;
|
||||
|
||||
pthread_mutex_lock(&(localnrf->usb_mutex));
|
||||
r = nrf_send_command_nb(caph, request, data, len);
|
||||
|
||||
if (r < 0) {
|
||||
printf("command send failed\n");
|
||||
pthread_mutex_unlock(&(localnrf->usb_mutex));
|
||||
return r;
|
||||
}
|
||||
|
||||
r = libusb_bulk_transfer(localnrf->nrf_handle, MOUSEJACK_USB_ENDPOINT_IN,
|
||||
rx_buf, 64, &actual_length, NRF_USB_TIMEOUT);
|
||||
|
||||
pthread_mutex_unlock(&(localnrf->usb_mutex));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int nrf_set_channel(kis_capture_handler_t *caph, uint8_t channel) {
|
||||
/* printf("channel %u\n", channel); */
|
||||
return nrf_send_command_with_resp(caph, MOUSEJACK_SET_CHANNEL, &channel, 1);
|
||||
}
|
||||
|
||||
int nrf_enter_promisc_mode(kis_capture_handler_t *caph, uint8_t *prefix, size_t prefix_len) {
|
||||
unsigned char *prefix_buf = NULL;
|
||||
int r;
|
||||
|
||||
if (prefix_len > 5)
|
||||
return -1;
|
||||
|
||||
prefix_buf = (unsigned char *) malloc(prefix_len + 1);
|
||||
prefix_buf[0] = prefix_len;
|
||||
|
||||
if (prefix_len > 0) {
|
||||
memcpy(prefix_buf + 1, prefix, prefix_len);
|
||||
}
|
||||
|
||||
r = nrf_send_command_with_resp(caph, MOUSEJACK_ENTER_PROMISCUOUS_MODE, prefix_buf, prefix_len + 1);
|
||||
|
||||
free(prefix_buf);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int nrf_enter_sniffer_mode(kis_capture_handler_t *caph, uint8_t *address, size_t addr_len) {
|
||||
unsigned char *addr_buf = (unsigned char *) malloc(addr_len + 1);
|
||||
int r;
|
||||
|
||||
addr_buf[0] = (uint8_t) addr_len;
|
||||
|
||||
if (addr_len > 0)
|
||||
memcpy(addr_buf + 1, address, addr_len);
|
||||
|
||||
r = nrf_send_command_with_resp(caph, MOUSEJACK_ENTER_SNIFFER_MODE, addr_buf, addr_len + 1);
|
||||
|
||||
free(addr_buf);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int nrf_receive_payload(kis_capture_handler_t *caph, uint8_t *rx_buf, size_t rx_max) {
|
||||
local_nrf_t *localnrf = (local_nrf_t *) caph->userdata;
|
||||
int actual_len, r;
|
||||
|
||||
pthread_mutex_lock(&(localnrf->usb_mutex));
|
||||
|
||||
r = nrf_send_command_nb(caph, MOUSEJACK_RECEIVE_PAYLOAD, NULL, 0);
|
||||
r = libusb_bulk_transfer(localnrf->nrf_handle, MOUSEJACK_USB_ENDPOINT_IN,
|
||||
rx_buf, rx_max, &actual_len, 0);
|
||||
|
||||
pthread_mutex_unlock(&(localnrf->usb_mutex));
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return actual_len;
|
||||
}
|
||||
|
||||
int nrf_enable_pa(kis_capture_handler_t *caph) {
|
||||
return nrf_send_command_with_resp(caph, MOUSEJACK_ENABLE_LNA_PA, NULL, 0);
|
||||
}
|
||||
|
||||
int probe_callback(kis_capture_handler_t *caph, uint32_t seqno, char *definition,
|
||||
char *msg, char **uuid, KismetExternal__Command *frame,
|
||||
cf_params_interface_t **ret_interface,
|
||||
cf_params_spectrum_t **ret_spectrum) {
|
||||
|
||||
char *placeholder = NULL;
|
||||
int placeholder_len;
|
||||
char *interface;
|
||||
char errstr[STATUS_MAX];
|
||||
|
||||
*ret_spectrum = NULL;
|
||||
*ret_interface = cf_params_interface_new();
|
||||
|
||||
int x;
|
||||
int busno = -1, devno = -1;
|
||||
|
||||
libusb_device **libusb_devs = NULL;
|
||||
ssize_t libusb_devices_cnt = 0;
|
||||
int r;
|
||||
|
||||
int matched_device = 0;
|
||||
|
||||
local_nrf_t *localnrf = (local_nrf_t *) caph->userdata;
|
||||
|
||||
if ((placeholder_len = cf_parse_interface(&placeholder, definition)) <= 0) {
|
||||
snprintf(msg, STATUS_MAX, "Unable to find interface in definition");
|
||||
return 0;
|
||||
}
|
||||
|
||||
interface = strndup(placeholder, placeholder_len);
|
||||
|
||||
/* Look for the interface type */
|
||||
if (strstr(interface, "mousejack") != interface) {
|
||||
free(interface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Look for interface-bus-dev */
|
||||
x = sscanf(interface, "mousejack-%d-%d", &busno, &devno);
|
||||
|
||||
free(interface);
|
||||
|
||||
/* printf("probe matched %d\n", x); */
|
||||
|
||||
/* If we don't have a valid busno/devno or malformed interface name */
|
||||
if (x != -1 && x != 2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
libusb_devices_cnt = libusb_get_device_list(localnrf->libusb_ctx, &libusb_devs);
|
||||
|
||||
if (libusb_devices_cnt < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (ssize_t i = 0; i < libusb_devices_cnt; i++) {
|
||||
struct libusb_device_descriptor dev;
|
||||
|
||||
r = libusb_get_device_descriptor(libusb_devs[i], &dev);
|
||||
|
||||
if (r < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dev.idVendor == MOUSEJACK_USB_VENDOR && dev.idProduct == MOUSEJACK_USB_PRODUCT) {
|
||||
if (busno >= 0) {
|
||||
if (busno == libusb_get_bus_number(libusb_devs[i]) &&
|
||||
devno == libusb_get_device_address(libusb_devs[i])) {
|
||||
matched_device = 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
matched_device = 1;
|
||||
busno = libusb_get_bus_number(libusb_devs[i]);
|
||||
devno = libusb_get_device_address(libusb_devs[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
libusb_free_device_list(libusb_devs, 1);
|
||||
|
||||
|
||||
/* Make a spoofed, but consistent, UUID based on the adler32 of the interface name
|
||||
* and the location in the bus */
|
||||
if ((placeholder_len = cf_find_flag(&placeholder, "uuid", definition)) > 0) {
|
||||
*uuid = strdup(placeholder);
|
||||
} else {
|
||||
snprintf(errstr, STATUS_MAX, "%08X-0000-0000-0000-%06X%06X",
|
||||
adler32_csum((unsigned char *) "kismet_cap_nrf_mousejack",
|
||||
strlen("kismet_cap_nrf_mousejack")) & 0xFFFFFFFF,
|
||||
busno, devno);
|
||||
*uuid = strdup(errstr);
|
||||
}
|
||||
|
||||
/* NRF supports 2-83 */
|
||||
(*ret_interface)->channels = (char **) malloc(sizeof(char *) * 82);
|
||||
for (int i = 2; i < 84; i++) {
|
||||
char chstr[4];
|
||||
snprintf(chstr, 4, "%d", i);
|
||||
(*ret_interface)->channels[i - 2] = strdup(chstr);
|
||||
}
|
||||
|
||||
(*ret_interface)->channels_len = 82;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int list_callback(kis_capture_handler_t *caph, uint32_t seqno,
|
||||
char *msg, cf_params_list_interface_t ***interfaces) {
|
||||
/* Basic list of devices */
|
||||
typedef struct nrf_list {
|
||||
char *device;
|
||||
struct nrf_list *next;
|
||||
} nrf_list_t;
|
||||
|
||||
nrf_list_t *devs = NULL;
|
||||
size_t num_devs = 0;
|
||||
|
||||
libusb_device **libusb_devs = NULL;
|
||||
ssize_t libusb_devices_cnt = 0;
|
||||
int r;
|
||||
|
||||
char devname[32];
|
||||
|
||||
unsigned int i;
|
||||
|
||||
local_nrf_t *localnrf = (local_nrf_t *) caph->userdata;
|
||||
|
||||
libusb_devices_cnt = libusb_get_device_list(localnrf->libusb_ctx, &libusb_devs);
|
||||
|
||||
if (libusb_devices_cnt < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (ssize_t i = 0; i < libusb_devices_cnt; i++) {
|
||||
struct libusb_device_descriptor dev;
|
||||
|
||||
r = libusb_get_device_descriptor(libusb_devs[i], &dev);
|
||||
|
||||
if (r < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dev.idVendor == MOUSEJACK_USB_VENDOR && dev.idProduct == MOUSEJACK_USB_PRODUCT) {
|
||||
snprintf(devname, 32, "mousejack-%u-%u",
|
||||
libusb_get_bus_number(libusb_devs[i]),
|
||||
libusb_get_device_address(libusb_devs[i]));
|
||||
|
||||
nrf_list_t *d = (nrf_list_t *) malloc(sizeof(nrf_list_t));
|
||||
num_devs++;
|
||||
d->device = strdup(devname);
|
||||
d->next = devs;
|
||||
devs = d;
|
||||
}
|
||||
}
|
||||
libusb_free_device_list(libusb_devs, 1);
|
||||
|
||||
if (num_devs == 0) {
|
||||
*interfaces = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*interfaces =
|
||||
(cf_params_list_interface_t **) malloc(sizeof(cf_params_list_interface_t *) * num_devs);
|
||||
|
||||
i = 0;
|
||||
|
||||
while (devs != NULL) {
|
||||
nrf_list_t *td = devs->next;
|
||||
(*interfaces)[i] = (cf_params_list_interface_t *) malloc(sizeof(cf_params_list_interface_t));
|
||||
memset((*interfaces)[i], 0, sizeof(cf_params_list_interface_t));
|
||||
|
||||
(*interfaces)[i]->interface = devs->device;
|
||||
(*interfaces)[i]->flags = NULL;
|
||||
(*interfaces)[i]->hardware = strdup("nrfmousejack");
|
||||
|
||||
free(devs);
|
||||
devs = td;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return num_devs;
|
||||
}
|
||||
|
||||
int open_callback(kis_capture_handler_t *caph, uint32_t seqno, char *definition,
|
||||
char *msg, uint32_t *dlt, char **uuid, KismetExternal__Command *frame,
|
||||
cf_params_interface_t **ret_interface,
|
||||
cf_params_spectrum_t **ret_spectrum) {
|
||||
|
||||
char *placeholder = NULL;
|
||||
int placeholder_len;
|
||||
char *interface;
|
||||
char errstr[STATUS_MAX];
|
||||
|
||||
*ret_spectrum = NULL;
|
||||
*ret_interface = cf_params_interface_new();
|
||||
|
||||
int x;
|
||||
int busno = -1, devno = -1;
|
||||
|
||||
libusb_device **libusb_devs = NULL;
|
||||
libusb_device *matched_dev = NULL;
|
||||
ssize_t libusb_devices_cnt = 0;
|
||||
int r;
|
||||
|
||||
int matched_device = 0;
|
||||
char cap_if[32];
|
||||
|
||||
local_nrf_t *localnrf = (local_nrf_t *) caph->userdata;
|
||||
|
||||
if ((placeholder_len = cf_parse_interface(&placeholder, definition)) <= 0) {
|
||||
snprintf(msg, STATUS_MAX, "Unable to find interface in definition");
|
||||
return 0;
|
||||
}
|
||||
|
||||
interface = strndup(placeholder, placeholder_len);
|
||||
|
||||
/* Look for the interface type */
|
||||
if (strstr(interface, "mousejack") != interface) {
|
||||
snprintf(msg, STATUS_MAX, "Unable to find mousejack interface");
|
||||
free(interface);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Look for interface-bus-dev */
|
||||
x = sscanf(interface, "mousejack-%d-%d", &busno, &devno);
|
||||
|
||||
free(interface);
|
||||
|
||||
/* If we don't have a valid busno/devno or malformed interface name */
|
||||
if (x != -1 && x != 2) {
|
||||
snprintf(msg, STATUS_MAX, "Malformed mousejack interface, expected 'mousejack' or "
|
||||
"'mousejack-bus#-dev#'");
|
||||
return -1;
|
||||
}
|
||||
|
||||
libusb_devices_cnt = libusb_get_device_list(localnrf->libusb_ctx, &libusb_devs);
|
||||
|
||||
if (libusb_devices_cnt < 0) {
|
||||
snprintf(msg, STATUS_MAX, "Unable to iterate USB devices");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (ssize_t i = 0; i < libusb_devices_cnt; i++) {
|
||||
struct libusb_device_descriptor dev;
|
||||
|
||||
r = libusb_get_device_descriptor(libusb_devs[i], &dev);
|
||||
|
||||
if (r < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dev.idVendor == MOUSEJACK_USB_VENDOR && dev.idProduct == MOUSEJACK_USB_PRODUCT) {
|
||||
if (busno >= 0) {
|
||||
if (busno == libusb_get_bus_number(libusb_devs[i]) &&
|
||||
devno == libusb_get_device_address(libusb_devs[i])) {
|
||||
matched_device = 1;
|
||||
matched_dev = libusb_devs[i];
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
matched_device = 1;
|
||||
busno = libusb_get_bus_number(libusb_devs[i]);
|
||||
devno = libusb_get_device_address(libusb_devs[i]);
|
||||
matched_dev = libusb_devs[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!matched_device) {
|
||||
snprintf(msg, STATUS_MAX, "Unable to find mousejack USB device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
libusb_free_device_list(libusb_devs, 1);
|
||||
|
||||
snprintf(cap_if, 32, "mousejack-%u-%u", busno, devno);
|
||||
|
||||
localnrf->devno = devno;
|
||||
localnrf->busno = busno;
|
||||
|
||||
/* Make a spoofed, but consistent, UUID based on the adler32 of the interface name
|
||||
* and the location in the bus */
|
||||
if ((placeholder_len = cf_find_flag(&placeholder, "uuid", definition)) > 0) {
|
||||
*uuid = strdup(placeholder);
|
||||
} else {
|
||||
snprintf(errstr, STATUS_MAX, "%08X-0000-0000-0000-%06X%06X",
|
||||
adler32_csum((unsigned char *) "kismet_cap_nrf_mousejack",
|
||||
strlen("kismet_cap_nrf_mousejack")) & 0xFFFFFFFF,
|
||||
busno, devno);
|
||||
*uuid = strdup(errstr);
|
||||
}
|
||||
|
||||
(*ret_interface)->capif = strdup(cap_if);
|
||||
(*ret_interface)->hardware = strdup("nrfmousejack");
|
||||
|
||||
/* NRF supports 2-83 */
|
||||
(*ret_interface)->channels = (char **) malloc(sizeof(char *) * 82);
|
||||
for (int i = 2; i < 84; i++) {
|
||||
char chstr[4];
|
||||
snprintf(chstr, 4, "%d", i);
|
||||
(*ret_interface)->channels[i - 2] = strdup(chstr);
|
||||
}
|
||||
|
||||
(*ret_interface)->channels_len = 82;
|
||||
|
||||
/* Try to open it */
|
||||
r = libusb_open(matched_dev, &localnrf->nrf_handle);
|
||||
if (r < 0) {
|
||||
snprintf(errstr, STATUS_MAX, "Unable to open mousejack USB interface: %s",
|
||||
libusb_strerror((enum libusb_error) r));
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Try to reset it */
|
||||
r = libusb_reset_device(localnrf->nrf_handle);
|
||||
|
||||
if (r < 0) {
|
||||
printf("reset failed\n");
|
||||
snprintf(errstr, STATUS_MAX, "Resetting USB device failed, continuing anyhow...");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Try to claim it */
|
||||
r = libusb_claim_interface(localnrf->nrf_handle, 0);
|
||||
if (r < 0) {
|
||||
if (r == LIBUSB_ERROR_BUSY) {
|
||||
/* Try to detach the kernel driver */
|
||||
r = libusb_detach_kernel_driver(localnrf->nrf_handle, 0);
|
||||
if (r < 0) {
|
||||
snprintf(errstr, STATUS_MAX, "Unable to open mousejack USB interface, and unable "
|
||||
"to disconnect existing driver: %s",
|
||||
libusb_strerror((enum libusb_error) r));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
snprintf(errstr, STATUS_MAX, "Unable to open mousejack USB interface: %s",
|
||||
libusb_strerror((enum libusb_error) r));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
libusb_set_configuration(localnrf->nrf_handle, 0);
|
||||
|
||||
nrf_enter_promisc_mode(caph, NULL, 0);
|
||||
nrf_enable_pa(caph);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *chantranslate_callback(kis_capture_handler_t *caph, char *chanstr) {
|
||||
local_channel_t *ret_localchan;
|
||||
unsigned int parsechan;
|
||||
char errstr[STATUS_MAX];
|
||||
|
||||
if (sscanf(chanstr, "%u", &parsechan) != 1) {
|
||||
snprintf(errstr, STATUS_MAX, "unable to parse requested channel '%s'; nrf channels "
|
||||
"are from 2 to 83", chanstr);
|
||||
cf_send_message(caph, errstr, MSGFLAG_INFO);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (parsechan < 2 || parsechan > 83) {
|
||||
snprintf(errstr, STATUS_MAX, "unable to parse requested channel '%u'; nrf channels "
|
||||
"are from 2 to 83", parsechan);
|
||||
cf_send_message(caph, errstr, MSGFLAG_INFO);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret_localchan = (local_channel_t *) malloc(sizeof(local_channel_t));
|
||||
ret_localchan->channel = parsechan;
|
||||
|
||||
return ret_localchan;
|
||||
}
|
||||
|
||||
int chancontrol_callback(kis_capture_handler_t *caph, uint32_t seqno, void *privchan,
|
||||
char *msg) {
|
||||
local_nrf_t *localnrf = (local_nrf_t *) caph->userdata;
|
||||
local_channel_t *channel = (local_channel_t *) privchan;
|
||||
|
||||
int r;
|
||||
|
||||
if (privchan == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = nrf_set_channel(caph, channel->channel);
|
||||
|
||||
if (r < 0)
|
||||
return -1;
|
||||
|
||||
localnrf->channel = channel->channel;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Run a standard glib mainloop inside the capture thread */
|
||||
void capture_thread(kis_capture_handler_t *caph) {
|
||||
local_nrf_t *localnrf = (local_nrf_t *) caph->userdata;
|
||||
|
||||
char errstr[STATUS_MAX];
|
||||
|
||||
/* mousejack should be 6 bytes of response + payload so this should be plenty of
|
||||
* space */
|
||||
uint8_t usb_buf[64];
|
||||
|
||||
int buf_rx_len, r;
|
||||
|
||||
while (1) {
|
||||
if (caph->spindown) {
|
||||
/* close usb */
|
||||
if (localnrf->nrf_handle) {
|
||||
libusb_close(localnrf->nrf_handle);
|
||||
localnrf->nrf_handle = NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
buf_rx_len = nrf_receive_payload(caph, usb_buf, 64);
|
||||
|
||||
if (buf_rx_len < 0) {
|
||||
snprintf(errstr, STATUS_MAX, "mousejack NRF interface 'mousejack-%u-%u' closed "
|
||||
"unexpectedly", localnrf->busno, localnrf->devno);
|
||||
cf_send_error(caph, 0, errstr);
|
||||
cf_handler_spindown(caph);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Skip runt packets caused by timeouts */
|
||||
if (buf_rx_len == 1)
|
||||
continue;
|
||||
|
||||
/*
|
||||
if (buf_rx_len > 1) {
|
||||
fprintf(stderr, "mousejack saw %d ", buf_rx_len);
|
||||
|
||||
for (int bb = 0; bb < buf_rx_len; bb++) {
|
||||
fprintf(stderr, "%02X ", usb_buf[bb] & 0xFF);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
*/
|
||||
|
||||
while (1) {
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
if ((r = cf_send_data(caph,
|
||||
NULL, NULL, NULL,
|
||||
tv,
|
||||
0,
|
||||
buf_rx_len, usb_buf)) < 0) {
|
||||
cf_send_error(caph, 0, "unable to send DATA frame");
|
||||
cf_handler_spindown(caph);
|
||||
} else if (r == 0) {
|
||||
cf_handler_wait_ringbuffer(caph);
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cf_handler_spindown(caph);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
local_nrf_t localnrf = {
|
||||
.libusb_ctx = NULL,
|
||||
.nrf_handle = NULL,
|
||||
.caph = NULL,
|
||||
};
|
||||
|
||||
pthread_mutex_init(&(localnrf.usb_mutex), NULL);
|
||||
|
||||
kis_capture_handler_t *caph = cf_handler_init("nrfmousejack");
|
||||
int r;
|
||||
|
||||
if (caph == NULL) {
|
||||
fprintf(stderr, "FATAL: Could not allocate basic handler data, your system "
|
||||
"is very low on RAM or something is wrong.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = libusb_init(&localnrf.libusb_ctx);
|
||||
if (r < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
localnrf.caph = caph;
|
||||
|
||||
/* Set the local data ptr */
|
||||
cf_handler_set_userdata(caph, &localnrf);
|
||||
|
||||
/* Set the callback for opening */
|
||||
cf_handler_set_open_cb(caph, open_callback);
|
||||
|
||||
/* Set the callback for probing an interface */
|
||||
cf_handler_set_probe_cb(caph, probe_callback);
|
||||
|
||||
/* Set the list callback */
|
||||
cf_handler_set_listdevices_cb(caph, list_callback);
|
||||
|
||||
/* Channel callbacks */
|
||||
cf_handler_set_chantranslate_cb(caph, chantranslate_callback);
|
||||
cf_handler_set_chancontrol_cb(caph, chancontrol_callback);
|
||||
|
||||
/* Set the capture thread */
|
||||
cf_handler_set_capture_cb(caph, capture_thread);
|
||||
|
||||
if (cf_handler_parse_opts(caph, argc, argv) < 1) {
|
||||
cf_print_help(caph, argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Support remote capture by launching the remote loop */
|
||||
cf_handler_remote_capture(caph);
|
||||
|
||||
/* Jail our ns */
|
||||
cf_jail_filesystem(caph);
|
||||
|
||||
/* Strip our privs */
|
||||
cf_drop_most_caps(caph);
|
||||
|
||||
cf_handler_loop(caph);
|
||||
|
||||
libusb_exit(localnrf.libusb_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
Derived from the Bastille Mousejack python code.
|
||||
While Kismet is generally licensed under the GPL2 license, this binary is
|
||||
derived from GPL3 code from Bastille, and as such, is under that license.
|
||||
|
||||
Copyright (C) 2016 Bastille Networks
|
||||
Copyright (C) 2018 Mike Kershaw / dragorn@kismetwireless.net
|
||||
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#ifndef __MOUSEJACK_H__
|
||||
#define __MOUSEJACK_H__
|
||||
|
||||
#define MOUSEJACK_USB_VENDOR 0x1915
|
||||
#define MOUSEJACK_USB_PRODUCT 0x0102
|
||||
|
||||
/* Protocol constants for the mousejack firmware */
|
||||
#define MOUSEJACK_TRANSMIT_PAYLOAD 0x04
|
||||
#define MOUSEJACK_ENTER_SNIFFER_MODE 0x05
|
||||
#define MOUSEJACK_ENTER_PROMISCUOUS_MODE 0x06
|
||||
#define MOUSEJACK_ENTER_TONE_TEST_MODE 0x07
|
||||
#define MOUSEJACK_TRANSMIT_ACK_PAYLOAD 0x08
|
||||
#define MOUSEJACK_SET_CHANNEL 0x09
|
||||
#define MOUSEJACK_GET_CHANNEL 0x0A
|
||||
#define MOUSEJACK_ENABLE_LNA_PA 0x0B
|
||||
#define MOUSEJACK_TRANSMIT_PAYLOAD_GENERIC 0x0C
|
||||
#define MOUSEJACK_ENTER_PROMISCUOUS_MODE_GENERIC 0x0D
|
||||
#define MOUSEJACK_RECEIVE_PAYLOAD 0x12
|
||||
|
||||
/* nRF registers */
|
||||
#define MOUSEJACK_RF_CH 0x05
|
||||
|
||||
/* Data rates */
|
||||
#define MOUSEJACK_RF_RATE_250K 0
|
||||
#define MOUSEJACK_RF_RATE_1M 1
|
||||
#define MOUSEJACK_RF_RATE_2M 2
|
||||
|
||||
/* Input endpoint */
|
||||
#define MOUSEJACK_USB_ENDPOINT_IN 0x81
|
||||
#define MOUSEJACK_USB_ENDPOINT_OUT 0x01
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
include ../Makefile.inc
|
||||
|
||||
MONITOR_OBJS = \
|
||||
../wifi_ht_channels.c.o \
|
||||
../interface_control.c.o
|
||||
|
||||
MONITOR_OBJC_OBJS = \
|
||||
capture_osx_corewlan_wifi.m.o
|
||||
|
||||
MONITOR_BIN = kismet_cap_osx_corewlan_wifi
|
||||
|
||||
PCAPLIBS=@pcaplnk@
|
||||
|
||||
CLANG=clang
|
||||
FRAMEWORKS=-framework Foundation -framework CoreWLAN
|
||||
|
||||
all: $(MONITOR_BIN)
|
||||
|
||||
$(MONITOR_BIN): $(MONITOR_OBJS) $(MONITOR_OBJC_OBJS) $(patsubst %c.o,%c.d,$(MONITOR_OBJS)) ../libkismetdatasource.a
|
||||
$(CLANG) $(FRAMEWORKS) -o $(MONITOR_BIN) $(MONITOR_OBJS) $(MONITOR_OBJC_OBJS) ../libkismetdatasource.a $(PCAPLIBS) $(NMLIBS) $(NETLINKLIBS) $(DATASOURCE_LIBS)
|
||||
|
||||
clean:
|
||||
@-rm -f $(MONITOR_BIN)
|
||||
@-rm -f *.o
|
||||
@-rm -f *.d
|
||||
|
||||
%.c.o: %.c
|
||||
%.c.o : %.c %.c.d
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) $(GLIBCFLAGS) $(DBUSGLIBCFLAGS) -c $*.c -o $@
|
||||
|
||||
%.c.d: %.c
|
||||
$(CC) -MM $(CFLAGS) $(GLIBCFLAGS) $(DBUSGLIBCFLAGS) $(CPPFLAGS) $*.c | sed -e "s/\.o/\.c.o/" > $*.c.d
|
||||
|
||||
%.m.o: %.m
|
||||
$(CLANG) $(CFLAGS) $(CPPFLAGS) -c $(FRAMEWORKS) $*.m -o $@
|
||||
|
||||
.PRECIOUS: %.c.d
|
||||
|
||||
include $(wildcard $(patsubst %c.o,%c.d,$(MONITOR_OBJS)))
|
||||
|
|
@ -1,808 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* capture_osx_corewlan_wifi
|
||||
*
|
||||
* Capture binary, written in a combination of pure c and objective c
|
||||
*
|
||||
* This talks to the corewlan API to get the available interfaces
|
||||
*
|
||||
*/
|
||||
|
||||
#include <pcap.h>
|
||||
#include <getopt.h>
|
||||
#include <pthread.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <sched.h>
|
||||
|
||||
/* According to POSIX.1-2001, POSIX.1-2008 */
|
||||
#include <sys/select.h>
|
||||
|
||||
/* According to earlier standards */
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <ifaddrs.h>
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#include "../capture_framework.h"
|
||||
#include "../interface_control.h"
|
||||
#include "../wifi_ht_channels.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreWLAN/CoreWLAN.h>
|
||||
|
||||
#define MAX_PACKET_LEN 8192
|
||||
|
||||
@interface CoreWLANHolder : NSObject
|
||||
@property (retain) CWInterface *interface;
|
||||
@property (retain) NSArray<CWChannel *> *channels;
|
||||
@end
|
||||
@implementation CoreWLANHolder
|
||||
@end
|
||||
|
||||
/* State tracking, put in userdata */
|
||||
typedef struct {
|
||||
pcap_t *pd;
|
||||
|
||||
char *interface;
|
||||
char *cap_interface;
|
||||
|
||||
int datalink_type;
|
||||
int override_dlt;
|
||||
|
||||
/* Number of sequential errors setting channel */
|
||||
unsigned int seq_channel_failure;
|
||||
|
||||
CoreWLANHolder *cw_holder;
|
||||
|
||||
} local_wifi_t;
|
||||
|
||||
int corewlan_find_channel(local_wifi_t *localwifi, int channel, int width) {
|
||||
int len = [[localwifi->cw_holder channels] count];
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
CWChannel *c = [localwifi->cw_holder channels][i];
|
||||
|
||||
if ([c channelNumber] == channel && [c channelWidth] == width) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int corewlan_set_channel(local_wifi_t *local_wifi, int pos) {
|
||||
CWChannel *c = [local_wifi->cw_holder channels][pos];
|
||||
CWInterface *i = [local_wifi->cw_holder interface];
|
||||
NSError *anyerror;
|
||||
BOOL r;
|
||||
|
||||
if (c == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = [i setWLANChannel:c
|
||||
error: &anyerror];
|
||||
|
||||
if (!r) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wi-Fi can use multiple channel widths and encodings which need to be
|
||||
* accounted for.
|
||||
*
|
||||
* Channel formats:
|
||||
*
|
||||
* XXW5 Channel/frequency XX, custom 5MHz channel
|
||||
* XXW10 Channel/frequency XX, custom 10MHz channel
|
||||
* XX Channel/frequency XX, non-HT standard 20MHz channel
|
||||
* XXHT40+ Channel/frequency XX, HT40+ channel
|
||||
* XXHT40- Channel/frequency XX, HT40- channel
|
||||
* XXVHT80 Channel/frequency XX, VHT 80MHz channel. Upper pair automatically
|
||||
* derived from channel definition table
|
||||
* XXVHT160 Channel/frequency XX, VHT 160MHz channel. Upper pair automatically
|
||||
* derived from channel definition table
|
||||
*
|
||||
* XXVHT80-YY Channel/frequency XX, VHT 80MHz channel, upper pair specified
|
||||
* XXVHT160-YY Channel/frequency XX, VHT 160MHz channel, upper pair specified
|
||||
*
|
||||
* We're not sure yet how to talk all these formats in OSX; more development to come;
|
||||
* for now, we do our best
|
||||
*
|
||||
*/
|
||||
|
||||
/* Local interpretation of a channel; this lets us parse the string definitions
|
||||
* into a faster non-parsed version, once. For OSX we need to track the original
|
||||
* channel object in swift because we can't reconstitute it */
|
||||
typedef struct {
|
||||
unsigned int channel;
|
||||
unsigned int width;
|
||||
int pos;
|
||||
} local_channel_t;
|
||||
|
||||
#define DARWIN_CHANWIDTH_UNKNOWN 0
|
||||
#define DARWIN_CHANWIDTH_20MHZ 1
|
||||
#define DARWIN_CHANWIDTH_40MHZ 2
|
||||
#define DARWIN_CHANWIDTH_80MHZ 3
|
||||
#define DARWIN_CHANWIDTH_160MHZ 4
|
||||
|
||||
/* Convert a string into a local interpretation; allocate ret_localchan.
|
||||
*/
|
||||
void *chantranslate_callback(kis_capture_handler_t *caph, char *chanstr) {
|
||||
local_wifi_t *local_wifi = (local_wifi_t *) caph->userdata;
|
||||
local_channel_t *ret_localchan = NULL;
|
||||
unsigned int parsechan, parse_center1;
|
||||
char parsetype[16];
|
||||
char mod;
|
||||
int r, pos;
|
||||
char errstr[STATUS_MAX];
|
||||
|
||||
/* Match HT40+ and HT40- */
|
||||
r = sscanf(chanstr, "%uHT40%c", &parsechan, &mod);
|
||||
|
||||
if (r == 2) {
|
||||
pos = corewlan_find_channel(local_wifi, parsechan, DARWIN_CHANWIDTH_40MHZ);
|
||||
|
||||
if (pos < 0) {
|
||||
snprintf(errstr, STATUS_MAX, "unable to find supported channel %s", chanstr);
|
||||
cf_send_message(caph, errstr, MSGFLAG_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret_localchan = (local_channel_t *) malloc(sizeof(local_channel_t));
|
||||
memset(ret_localchan, 0, sizeof(local_channel_t));
|
||||
|
||||
/* We set the width and let OSX figure it out */
|
||||
(ret_localchan)->channel = parsechan;
|
||||
(ret_localchan)->width = DARWIN_CHANWIDTH_40MHZ;
|
||||
(ret_localchan)->pos = pos;
|
||||
|
||||
return ret_localchan;
|
||||
}
|
||||
|
||||
|
||||
/* otherwise parse VHTXX, WXX, and VHTXX-YYY */
|
||||
r = sscanf(chanstr, "%u%15[^-]-%u", &parsechan, parsetype, &parse_center1);
|
||||
|
||||
if (r <= 0) {
|
||||
snprintf(errstr, STATUS_MAX, "unable to parse any channel information from "
|
||||
"channel string '%s'", chanstr);
|
||||
cf_send_message(caph, errstr, MSGFLAG_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (r == 1) {
|
||||
pos = corewlan_find_channel(local_wifi, parsechan, DARWIN_CHANWIDTH_20MHZ);
|
||||
|
||||
if (pos < 0) {
|
||||
snprintf(errstr, STATUS_MAX, "unable to find supported channel %s", chanstr);
|
||||
cf_send_message(caph, errstr, MSGFLAG_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret_localchan = (local_channel_t *) malloc(sizeof(local_channel_t));
|
||||
memset(ret_localchan, 0, sizeof(local_channel_t));
|
||||
|
||||
ret_localchan->channel = parsechan;
|
||||
ret_localchan->width = DARWIN_CHANWIDTH_20MHZ;
|
||||
ret_localchan->pos = pos;
|
||||
|
||||
return ret_localchan;
|
||||
}
|
||||
|
||||
if (r >= 2) {
|
||||
ret_localchan = (local_channel_t *) malloc(sizeof(local_channel_t));
|
||||
memset(ret_localchan, 0, sizeof(local_channel_t));
|
||||
|
||||
ret_localchan->channel = parsechan;
|
||||
|
||||
if (strcasecmp(parsetype, "vht80") == 0) {
|
||||
pos = corewlan_find_channel(local_wifi, parsechan, DARWIN_CHANWIDTH_80MHZ);
|
||||
|
||||
if (pos < 0) {
|
||||
free(ret_localchan);
|
||||
snprintf(errstr, STATUS_MAX, "unable to find supported channel %s", chanstr);
|
||||
cf_send_message(caph, errstr, MSGFLAG_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret_localchan->width = DARWIN_CHANWIDTH_80MHZ;
|
||||
ret_localchan->pos = pos;
|
||||
} else if (strcasecmp(parsetype, "vht160") == 0) {
|
||||
pos = corewlan_find_channel(local_wifi, parsechan, DARWIN_CHANWIDTH_160MHZ);
|
||||
|
||||
if (pos < 0) {
|
||||
free(ret_localchan);
|
||||
snprintf(errstr, STATUS_MAX, "unable to find supported channel %s", chanstr);
|
||||
cf_send_message(caph, errstr, MSGFLAG_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret_localchan->width = DARWIN_CHANWIDTH_160MHZ;
|
||||
ret_localchan->pos = pos;
|
||||
} else {
|
||||
free(ret_localchan);
|
||||
snprintf(errstr, STATUS_MAX, "unable to parse channel %s", chanstr);
|
||||
cf_send_message(caph, errstr, MSGFLAG_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret_localchan;
|
||||
}
|
||||
|
||||
/* Convert a local interpretation of a channel back info a string;
|
||||
* 'chanstr' should hold at least STATUS_MAX characters; we'll never use
|
||||
* that many but it lets us do some cheaty stuff and re-use errstrs */
|
||||
void local_channel_to_str(local_channel_t *chan, char *chanstr) {
|
||||
/* Basic channel with no HT/VHT */
|
||||
switch (chan->width) {
|
||||
case DARWIN_CHANWIDTH_UNKNOWN:
|
||||
case DARWIN_CHANWIDTH_20MHZ:
|
||||
case DARWIN_CHANWIDTH_40MHZ:
|
||||
snprintf(chanstr, STATUS_MAX, "%u", chan->channel);
|
||||
break;
|
||||
case DARWIN_CHANWIDTH_80MHZ:
|
||||
snprintf(chanstr, STATUS_MAX, "%uVHT80", chan->channel);
|
||||
break;
|
||||
case DARWIN_CHANWIDTH_160MHZ:
|
||||
snprintf(chanstr, STATUS_MAX, "%uVHT160", chan->channel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int populate_chanlist(local_wifi_t *local_wifi, char *interface, char *msg, char ***chanlist,
|
||||
size_t *chanlist_sz) {
|
||||
char conv_chan[16];
|
||||
int num_chans;
|
||||
CWChannel *c;
|
||||
int ci;
|
||||
|
||||
[local_wifi->cw_holder setChannels:[[[local_wifi->cw_holder interface] supportedWLANChannels] allObjects]];
|
||||
num_chans = [[local_wifi->cw_holder channels] count];
|
||||
|
||||
if (num_chans <= 0) {
|
||||
*chanlist = NULL;
|
||||
*chanlist_sz = 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Now we build our list and do it all again */
|
||||
*chanlist = (char **) malloc(sizeof(char *) * num_chans);
|
||||
*chanlist_sz = num_chans;
|
||||
|
||||
for (ci = 0; ci < num_chans; ci++) {
|
||||
c = [local_wifi->cw_holder channels][ci];
|
||||
|
||||
switch ([c channelWidth]) {
|
||||
case DARWIN_CHANWIDTH_UNKNOWN:
|
||||
case DARWIN_CHANWIDTH_20MHZ:
|
||||
snprintf(conv_chan, 16, "%ld", [c channelNumber]);
|
||||
(*chanlist)[ci] = strdup(conv_chan);
|
||||
break;
|
||||
case DARWIN_CHANWIDTH_40MHZ:
|
||||
/* Make sure we can set ht80 */
|
||||
if ([c channelNumber] > 0 && [c channelNumber] < MAX_WIFI_HT_CHANNEL) {
|
||||
if (wifi_ht_channels[[c channelNumber]].flags & WIFI_HT_HT40MINUS) {
|
||||
snprintf(conv_chan, 16, "%ldHT40-", [c channelNumber]);
|
||||
} else {
|
||||
snprintf(conv_chan, 16, "%ldHT40+", [c channelNumber]);
|
||||
}
|
||||
|
||||
(*chanlist)[ci] = strdup(conv_chan);
|
||||
}
|
||||
(*chanlist)[ci] = strdup(conv_chan);
|
||||
break;
|
||||
case DARWIN_CHANWIDTH_80MHZ:
|
||||
snprintf(conv_chan, 16, "%ldVHT80", [c channelNumber]);
|
||||
(*chanlist)[ci] = strdup(conv_chan);
|
||||
break;
|
||||
case DARWIN_CHANWIDTH_160MHZ:
|
||||
snprintf(conv_chan, 16, "%ldVHT160", [c channelNumber]);
|
||||
(*chanlist)[ci] = strdup(conv_chan);
|
||||
break;
|
||||
default:
|
||||
printf("unknown channel\n");
|
||||
(*chanlist)[ci] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Channel control callback; actually set a channel. Determines if our
|
||||
* custom channel needs a VHT frequency set. */
|
||||
int chancontrol_callback(kis_capture_handler_t *caph, uint32_t seqno, void *privchan,
|
||||
char *msg) {
|
||||
local_wifi_t *local_wifi = (local_wifi_t *) caph->userdata;
|
||||
local_channel_t *channel = (local_channel_t *) privchan;
|
||||
char errstr[STATUS_MAX];
|
||||
char chanstr[STATUS_MAX];
|
||||
|
||||
if (privchan == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (corewlan_set_channel(local_wifi, channel->pos) < 0) {
|
||||
local_channel_to_str(channel, chanstr);
|
||||
snprintf(msg, STATUS_MAX, "failed to set channel %s: %s",
|
||||
chanstr, errstr);
|
||||
|
||||
if (seqno == 0) {
|
||||
cf_send_error(caph, 0, msg);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int probe_callback(kis_capture_handler_t *caph, uint32_t seqno, char *definition,
|
||||
char *msg, char **uuid, KismetExternal__Command *frame,
|
||||
cf_params_interface_t **ret_interface,
|
||||
cf_params_spectrum_t **ret_spectrum) {
|
||||
local_wifi_t *local_wifi = (local_wifi_t *) caph->userdata;
|
||||
char *placeholder = NULL;
|
||||
int placeholder_len;
|
||||
char *interface;
|
||||
int ret, i;
|
||||
char errstr[STATUS_MAX];
|
||||
int found_interface = 0;
|
||||
|
||||
*ret_spectrum = NULL;
|
||||
*ret_interface = cf_params_interface_new();
|
||||
|
||||
uint8_t hwaddr[6];
|
||||
|
||||
NSArray<CWInterface *> *cw_interfaces =
|
||||
[[CWWiFiClient sharedWiFiClient] interfaces];
|
||||
|
||||
if ((placeholder_len = cf_parse_interface(&placeholder, definition)) <= 0) {
|
||||
snprintf(msg, STATUS_MAX, "Unable to find interface in definition");
|
||||
return 0;
|
||||
}
|
||||
|
||||
interface = strndup(placeholder, placeholder_len);
|
||||
|
||||
/* Look for the interface */
|
||||
for (i = 0; i < [cw_interfaces count]; i++) {
|
||||
if (strcmp([[cw_interfaces[i] interfaceName] UTF8String], interface) == 0) {
|
||||
[local_wifi->cw_holder setInterface:cw_interfaces[i]];
|
||||
found_interface = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_interface) {
|
||||
free(interface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* get the mac address; this should be standard for anything */
|
||||
if (ifconfig_get_hwaddr(interface, errstr, hwaddr) < 0) {
|
||||
free(interface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = populate_chanlist(local_wifi, interface, errstr, &((*ret_interface)->channels),
|
||||
&((*ret_interface)->channels_len));
|
||||
|
||||
free(interface);
|
||||
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
|
||||
/* Make a spoofed, but consistent, UUID based on the adler32 of the interface name
|
||||
* and the mac address of the device */
|
||||
if ((placeholder_len = cf_find_flag(&placeholder, "uuid", definition)) > 0) {
|
||||
*uuid = strdup(placeholder);
|
||||
} else {
|
||||
snprintf(errstr, STATUS_MAX, "%08X-0000-0000-0000-%02X%02X%02X%02X%02X%02X",
|
||||
adler32_csum((unsigned char *) "kismet_cap_osx_corewlan_wifi",
|
||||
strlen("kismet_cap_osx_corewlan_wifi")) & 0xFFFFFFFF,
|
||||
hwaddr[0] & 0xFF, hwaddr[1] & 0xFF, hwaddr[2] & 0xFF,
|
||||
hwaddr[3] & 0xFF, hwaddr[4] & 0xFF, hwaddr[5] & 0xFF);
|
||||
*uuid = strdup(errstr);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int open_callback(kis_capture_handler_t *caph, uint32_t seqno, char *definition,
|
||||
char *msg, uint32_t *dlt, char **uuid, KismetExternal__Command *frame,
|
||||
cf_params_interface_t **ret_interface,
|
||||
cf_params_spectrum_t **ret_spectrum) {
|
||||
|
||||
local_wifi_t *local_wifi = (local_wifi_t *) caph->userdata;
|
||||
|
||||
char *placeholder = NULL;
|
||||
int placeholder_len;
|
||||
|
||||
uint8_t hwaddr[6];
|
||||
|
||||
char errstr[STATUS_MAX];
|
||||
char pcap_errstr[PCAP_ERRBUF_SIZE] = "";
|
||||
|
||||
*uuid = NULL;
|
||||
*dlt = 0;
|
||||
|
||||
*ret_interface = cf_params_interface_new();
|
||||
*ret_spectrum = NULL;
|
||||
|
||||
int ret, i, found_interface = 0;
|
||||
|
||||
char *localchanstr = NULL;
|
||||
local_channel_t *localchan = NULL;
|
||||
|
||||
NSArray<CWInterface *> *cw_interfaces =
|
||||
[[CWWiFiClient sharedWiFiClient] interfaces];
|
||||
|
||||
/* Clean up any existing local state on open; we can get re-opened if we're a
|
||||
* remote source */
|
||||
if (local_wifi->interface) {
|
||||
free(local_wifi->interface);
|
||||
local_wifi->interface = NULL;
|
||||
}
|
||||
|
||||
if (local_wifi->cap_interface) {
|
||||
free(local_wifi->cap_interface);
|
||||
local_wifi->cap_interface = NULL;
|
||||
}
|
||||
|
||||
if (local_wifi->pd != NULL) {
|
||||
pcap_close(local_wifi->pd);
|
||||
local_wifi->pd = NULL;
|
||||
}
|
||||
|
||||
/* Start processing the open */
|
||||
|
||||
if ((placeholder_len = cf_parse_interface(&placeholder, definition)) <= 0) {
|
||||
snprintf(msg, STATUS_MAX, "Unable to find interface in definition");
|
||||
return -1;
|
||||
}
|
||||
|
||||
local_wifi->interface = strndup(placeholder, placeholder_len);
|
||||
|
||||
/* Look for the interface */
|
||||
for (i = 0; i < [cw_interfaces count]; i++) {
|
||||
if (strcmp([[cw_interfaces[i] interfaceName] UTF8String], local_wifi->interface) == 0) {
|
||||
[local_wifi->cw_holder setInterface:cw_interfaces[i]];
|
||||
found_interface = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_interface) {
|
||||
snprintf(msg, STATUS_MAX, "Unable to find interface %s via the OSX CoreWLAN system",
|
||||
local_wifi->interface);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* get the mac address; this should be standard for anything */
|
||||
if (ifconfig_get_hwaddr(local_wifi->interface, errstr, hwaddr) < 0) {
|
||||
snprintf(msg, STATUS_MAX, "Could not fetch interface address from '%s': %s",
|
||||
local_wifi->interface, errstr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Make a spoofed, but consistent, UUID based on the adler32 of the interface name
|
||||
* and the mac address of the device */
|
||||
if ((placeholder_len = cf_find_flag(&placeholder, "uuid", definition)) > 0) {
|
||||
*uuid = strdup(placeholder);
|
||||
} else {
|
||||
snprintf(errstr, STATUS_MAX, "%08X-0000-0000-0000-%02X%02X%02X%02X%02X%02X",
|
||||
adler32_csum((unsigned char *) "kismet_cap_osx_corewlan_wifi",
|
||||
strlen("kismet_cap_osx_corewlan_wifi")) & 0xFFFFFFFF,
|
||||
hwaddr[0] & 0xFF, hwaddr[1] & 0xFF, hwaddr[2] & 0xFF,
|
||||
hwaddr[3] & 0xFF, hwaddr[4] & 0xFF, hwaddr[5] & 0xFF);
|
||||
*uuid = strdup(errstr);
|
||||
}
|
||||
|
||||
local_wifi->cap_interface = strdup(local_wifi->interface);
|
||||
|
||||
/* Bring up the cap interface no matter what */
|
||||
if (ifconfig_interface_up(local_wifi->cap_interface, errstr) != 0) {
|
||||
snprintf(msg, STATUS_MAX, "Could not bring up capture interface '%s', "
|
||||
"check 'dmesg' for possible errors while loading firmware: %s",
|
||||
local_wifi->cap_interface, errstr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = populate_chanlist(local_wifi, local_wifi->cap_interface, errstr,
|
||||
&((*ret_interface)->channels), &((*ret_interface)->channels_len));
|
||||
|
||||
if (ret < 0) {
|
||||
snprintf(msg, STATUS_MAX, "Could not get list of channels from capture "
|
||||
"interface '%s' on '%s': %s", local_wifi->cap_interface,
|
||||
local_wifi->interface, errstr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
[[local_wifi->cw_holder interface] disassociate];
|
||||
|
||||
/* Open the pcap */
|
||||
local_wifi->pd = pcap_create(local_wifi->cap_interface, pcap_errstr);
|
||||
|
||||
if (local_wifi->pd == NULL || strlen(pcap_errstr) != 0) {
|
||||
snprintf(msg, STATUS_MAX, "Could not open capture interface '%s' on '%s' "
|
||||
"as a pcap capture: %s", local_wifi->cap_interface,
|
||||
local_wifi->interface, pcap_errstr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pcap_can_set_rfmon(local_wifi->pd)) {
|
||||
printf("think we can set monitor\n");
|
||||
} else {
|
||||
printf("don't think we can set monitor\n");
|
||||
}
|
||||
|
||||
|
||||
if (pcap_set_rfmon(local_wifi->pd, 1) < 0) {
|
||||
printf("set rfmon failed\n");
|
||||
/*
|
||||
snprintf(msg, STATUS_MAX,
|
||||
"Could not enable monitor mode on interface '%s'",
|
||||
local_wifi->interface);
|
||||
return -1;
|
||||
*/
|
||||
}
|
||||
|
||||
pcap_set_promisc(local_wifi->pd, 1);
|
||||
pcap_set_snaplen(local_wifi->pd, MAX_PACKET_LEN);
|
||||
pcap_set_timeout(local_wifi->pd, 1000);
|
||||
|
||||
pcap_activate(local_wifi->pd);
|
||||
|
||||
local_wifi->datalink_type = pcap_datalink(local_wifi->pd);
|
||||
*dlt = local_wifi->datalink_type;
|
||||
|
||||
snprintf(msg, STATUS_MAX, "OSX Wi-Fi capturing from interface '%s'",
|
||||
local_wifi->interface);
|
||||
|
||||
if ((placeholder_len =
|
||||
cf_find_flag(&placeholder, "channel", definition)) > 0) {
|
||||
localchanstr = strndup(placeholder, placeholder_len);
|
||||
|
||||
localchan =
|
||||
(local_channel_t *) chantranslate_callback(caph, localchanstr);
|
||||
|
||||
free(localchanstr);
|
||||
|
||||
if (localchan == NULL) {
|
||||
snprintf(msg, STATUS_MAX,
|
||||
"Could not parse channel= option provided in source "
|
||||
"definition");
|
||||
return -1;
|
||||
}
|
||||
|
||||
local_channel_to_str(localchan, errstr);
|
||||
(*ret_interface)->chanset = strdup(errstr);
|
||||
|
||||
snprintf(errstr, STATUS_MAX, "Setting initial channel to %s",
|
||||
(*ret_interface)->chanset);
|
||||
cf_send_message(caph, errstr, MSGFLAG_INFO);
|
||||
|
||||
if (chancontrol_callback(caph, 0, localchan, msg) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
(*ret_interface)->capif = strdup(local_wifi->cap_interface);
|
||||
(*ret_interface)->hardware = strdup("osxcorewlan");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int list_callback(kis_capture_handler_t *caph, uint32_t seqno,
|
||||
char *msg, cf_params_list_interface_t ***interfaces) {
|
||||
|
||||
NSArray<CWInterface *> *cw_interfaces =
|
||||
[[CWWiFiClient sharedWiFiClient] interfaces];
|
||||
|
||||
int num_corewlan_devs;
|
||||
int di;
|
||||
|
||||
num_corewlan_devs = [cw_interfaces count];
|
||||
|
||||
if (num_corewlan_devs <= 0)
|
||||
return 0;
|
||||
|
||||
*interfaces =
|
||||
(cf_params_list_interface_t **) malloc(sizeof(cf_params_list_interface_t *) *
|
||||
num_corewlan_devs);
|
||||
|
||||
for (di = 0; di < num_corewlan_devs; di++) {
|
||||
(*interfaces)[di] = (cf_params_list_interface_t *) malloc(sizeof(cf_params_list_interface_t));
|
||||
memset((*interfaces)[di], 0, sizeof(cf_params_list_interface_t));
|
||||
|
||||
(*interfaces)[di]->interface = strdup([[cw_interfaces[di] interfaceName] UTF8String]);
|
||||
(*interfaces)[di]->flags = NULL;
|
||||
(*interfaces)[di]->hardware = strdup("osxcorewlan");
|
||||
}
|
||||
|
||||
return num_corewlan_devs;
|
||||
}
|
||||
|
||||
void pcap_dispatch_cb(u_char *user, const struct pcap_pkthdr *header,
|
||||
const u_char *data) {
|
||||
kis_capture_handler_t *caph = (kis_capture_handler_t *) user;
|
||||
local_wifi_t *local_wifi = (local_wifi_t *) caph->userdata;
|
||||
int ret;
|
||||
|
||||
/* Try repeatedly to send the packet; go into a thread wait state if
|
||||
* the write buffer is full & we'll be woken up as soon as it flushes
|
||||
* data out in the main select() loop */
|
||||
while (1) {
|
||||
if ((ret = cf_send_data(caph,
|
||||
NULL, NULL, NULL,
|
||||
header->ts,
|
||||
local_wifi->datalink_type,
|
||||
header->caplen, (uint8_t *) data)) < 0) {
|
||||
pcap_breakloop(local_wifi->pd);
|
||||
cf_send_error(caph, 0, "unable to send DATA frame");
|
||||
cf_handler_spindown(caph);
|
||||
} else if (ret == 0) {
|
||||
/* Go into a wait for the write buffer to get flushed */
|
||||
cf_handler_wait_ringbuffer(caph);
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void capture_thread(kis_capture_handler_t *caph) {
|
||||
local_wifi_t *local_wifi = (local_wifi_t *) caph->userdata;
|
||||
char errstr[PCAP_ERRBUF_SIZE];
|
||||
char *pcap_errstr;
|
||||
char iferrstr[STATUS_MAX];
|
||||
int ifflags = 0, ifret;
|
||||
|
||||
/* Simple capture thread: since we don't care about blocking and
|
||||
* channel control is managed by the channel hopping thread, all we have
|
||||
* to do is enter a blocking pcap loop */
|
||||
|
||||
pcap_loop(local_wifi->pd, -1, pcap_dispatch_cb, (u_char *) caph);
|
||||
|
||||
pcap_errstr = pcap_geterr(local_wifi->pd);
|
||||
|
||||
snprintf(errstr, PCAP_ERRBUF_SIZE, "Interface '%s' closed: %s",
|
||||
local_wifi->cap_interface,
|
||||
strlen(pcap_errstr) == 0 ? "interface closed" : pcap_errstr );
|
||||
|
||||
cf_send_error(caph, 0, errstr);
|
||||
|
||||
ifret = ifconfig_get_flags(local_wifi->cap_interface, iferrstr, &ifflags);
|
||||
|
||||
if (ifret < 0 || !(ifflags & IFF_UP)) {
|
||||
snprintf(errstr, PCAP_ERRBUF_SIZE, "Interface '%s' no longer appears to be up; "
|
||||
"This can happen when it is unplugged, or another service like DHCP or "
|
||||
"has taken over and shut it down on us.", local_wifi->cap_interface);
|
||||
cf_send_error(caph, 0, errstr);
|
||||
}
|
||||
|
||||
cf_handler_spindown(caph);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
local_wifi_t local_wifi = {
|
||||
.pd = NULL,
|
||||
.interface = NULL,
|
||||
.cap_interface = NULL,
|
||||
.datalink_type = -1,
|
||||
.override_dlt = -1,
|
||||
.seq_channel_failure = 0,
|
||||
.cw_holder = NULL
|
||||
};
|
||||
|
||||
#if 0
|
||||
/* Remap stderr so we can log debugging to a file */
|
||||
FILE *sterr;
|
||||
sterr = fopen("/tmp/capture_linux_wifi.stderr", "a");
|
||||
dup2(fileno(sterr), STDERR_FILENO);
|
||||
dup2(fileno(sterr), STDOUT_FILENO);
|
||||
#endif
|
||||
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
CoreWLANHolder *holder = [CoreWLANHolder alloc];
|
||||
local_wifi.cw_holder = holder;
|
||||
|
||||
kis_capture_handler_t *caph = cf_handler_init("osxcorewlanwifi");
|
||||
|
||||
if (caph == NULL) {
|
||||
fprintf(stderr, "FATAL: Could not allocate basic handler data, your system "
|
||||
"is very low on RAM or something is wrong.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set the local data ptr */
|
||||
cf_handler_set_userdata(caph, &local_wifi);
|
||||
|
||||
/* Set the callback for opening */
|
||||
cf_handler_set_open_cb(caph, open_callback);
|
||||
|
||||
/* Set the callback for probing an interface */
|
||||
cf_handler_set_probe_cb(caph, probe_callback);
|
||||
|
||||
/* Set the list callback */
|
||||
cf_handler_set_listdevices_cb(caph, list_callback);
|
||||
|
||||
/* Set the translation cb */
|
||||
cf_handler_set_chantranslate_cb(caph, chantranslate_callback);
|
||||
|
||||
/* Set the control cb */
|
||||
cf_handler_set_chancontrol_cb(caph, chancontrol_callback);
|
||||
|
||||
/* Set the capture thread */
|
||||
cf_handler_set_capture_cb(caph, capture_thread);
|
||||
|
||||
/* Set a channel hop spacing of 4 to get the most out of 2.4 overlap;
|
||||
* it does nothing and hurts nothing on 5ghz */
|
||||
cf_handler_set_hop_shuffle_spacing(caph, 4);
|
||||
|
||||
if (cf_handler_parse_opts(caph, argc, argv) < 1) {
|
||||
cf_print_help(caph, argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Support remote capture by launching the remote loop */
|
||||
cf_handler_remote_capture(caph);
|
||||
|
||||
#if 0
|
||||
/* Jail our ns */
|
||||
if (cf_jail_filesystem(caph) < 1) {
|
||||
fprintf(stderr, "DEBUG - Couldn't jail filesystem\n");
|
||||
}
|
||||
|
||||
/* Strip our privs */
|
||||
if (cf_drop_most_caps(caph) < 1) {
|
||||
fprintf(stderr, "DEBUG - Didn't drop some privs\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
cf_handler_loop(caph);
|
||||
|
||||
cf_handler_free(caph);
|
||||
|
||||
[pool drain];
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -1,391 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* capture_pcapfile
|
||||
*
|
||||
* Basic capture binary, written in pure C, which interfaces via the Kismet
|
||||
* simple capture protocol and feeds packets from a pcap file.
|
||||
*
|
||||
* This could have been implemented in C++ but serves as an example of a simple,
|
||||
* very low resource capture method.
|
||||
*
|
||||
* This uses some of the pure-C code included in Kismet - pure-c implementations
|
||||
* of the datasource protocol, a basic ringbuffer implementation, and the msgpuck
|
||||
* library which is a pure-c simple msgpack library.
|
||||
*
|
||||
* This uses basic threading to show how to do an asynchronous read from a source;
|
||||
* while a pcapfile will never stall, other sources could.
|
||||
*
|
||||
* The select() loop for IO with the IPC channel is performed in the primary
|
||||
* thread, and an IO thread is spawned to process data from the pcap file. This
|
||||
* allows us to expand to interesting options, like realtime pcap replay which
|
||||
* delays the IO as if they were real packets.
|
||||
*
|
||||
* The DLT is automatically propagated from the pcap file, or can be overridden
|
||||
* with a source command.
|
||||
*
|
||||
* The communications channel is a file descriptor pair, passed via command
|
||||
* line arguments, --in-fd= and --out-fd=
|
||||
*
|
||||
* We parse additional options from the source definition itself, such as a DLT
|
||||
* override, once we open the protocol
|
||||
*
|
||||
*/
|
||||
|
||||
#include <pcap.h>
|
||||
#include <getopt.h>
|
||||
#include <pthread.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
/* According to POSIX.1-2001, POSIX.1-2008 */
|
||||
#include <sys/select.h>
|
||||
|
||||
/* According to earlier standards */
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "capture_framework.h"
|
||||
|
||||
typedef struct {
|
||||
pcap_t *pd;
|
||||
char *pcapfname;
|
||||
int datalink_type;
|
||||
int override_dlt;
|
||||
|
||||
int realtime;
|
||||
struct timeval last_ts;
|
||||
|
||||
unsigned int pps_throttle;
|
||||
} local_pcap_t;
|
||||
|
||||
int probe_callback(kis_capture_handler_t *caph, uint32_t seqno, char *definition,
|
||||
char *msg, char **uuid, KismetExternal__Command *frame,
|
||||
cf_params_interface_t **ret_interface,
|
||||
cf_params_spectrum_t **ret_spectrum) {
|
||||
char *placeholder = NULL;
|
||||
int placeholder_len;
|
||||
|
||||
*uuid = NULL;
|
||||
|
||||
char *pcapfname = NULL;
|
||||
|
||||
struct stat sbuf;
|
||||
|
||||
char errstr[PCAP_ERRBUF_SIZE] = "";
|
||||
|
||||
pcap_t *pd;
|
||||
|
||||
*ret_spectrum = NULL;
|
||||
|
||||
*ret_interface = cf_params_interface_new();
|
||||
*ret_spectrum = NULL;
|
||||
|
||||
/* pcapfile does not support channel ops */
|
||||
(*ret_interface)->chanset = NULL;
|
||||
(*ret_interface)->channels = NULL;
|
||||
(*ret_interface)->channels_len = 0;
|
||||
|
||||
if ((placeholder_len = cf_parse_interface(&placeholder, definition)) <= 0) {
|
||||
snprintf(msg, STATUS_MAX, "Unable to find PCAP file name in definition");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pcapfname = strndup(placeholder, placeholder_len);
|
||||
|
||||
if (stat(pcapfname, &sbuf) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!S_ISREG(sbuf.st_mode)) {
|
||||
snprintf(msg, STATUS_MAX, "File '%s' is not a regular file", pcapfname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pd = pcap_open_offline(pcapfname, errstr);
|
||||
if (strlen(errstr) > 0) {
|
||||
snprintf(msg, STATUS_MAX, "%s", errstr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pcap_close(pd);
|
||||
|
||||
if ((placeholder_len = cf_find_flag(&placeholder, "uuid", definition)) > 0) {
|
||||
*uuid = strdup(placeholder);
|
||||
} else {
|
||||
/* Kluge a UUID out of the name */
|
||||
snprintf(errstr, PCAP_ERRBUF_SIZE, "%08X-0000-0000-0000-0000%08X",
|
||||
adler32_csum((unsigned char *) "kismet_cap_pcapfile",
|
||||
strlen("kismet_cap_pcapfile")) & 0xFFFFFFFF,
|
||||
adler32_csum((unsigned char *) pcapfname,
|
||||
strlen(pcapfname)) & 0xFFFFFFFF);
|
||||
*uuid = strdup(errstr);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int open_callback(kis_capture_handler_t *caph, uint32_t seqno, char *definition,
|
||||
char *msg, uint32_t *dlt, char **uuid, KismetExternal__Command *frame,
|
||||
cf_params_interface_t **ret_interface,
|
||||
cf_params_spectrum_t **ret_spectrum) {
|
||||
char *placeholder = NULL;
|
||||
int placeholder_len;
|
||||
|
||||
char *pcapfname = NULL;
|
||||
|
||||
struct stat sbuf;
|
||||
|
||||
local_pcap_t *local_pcap = (local_pcap_t *) caph->userdata;
|
||||
|
||||
char errstr[PCAP_ERRBUF_SIZE] = "";
|
||||
|
||||
/* pcapfile does not support channel ops */
|
||||
*ret_interface = cf_params_interface_new();
|
||||
*ret_spectrum = NULL;
|
||||
|
||||
*uuid = NULL;
|
||||
*dlt = 0;
|
||||
|
||||
/* Clean up any old state */
|
||||
if (local_pcap->pcapfname != NULL) {
|
||||
free(local_pcap->pcapfname);
|
||||
local_pcap->pcapfname = NULL;
|
||||
}
|
||||
|
||||
if (local_pcap->pd != NULL) {
|
||||
pcap_close(local_pcap->pd);
|
||||
local_pcap->pd = NULL;
|
||||
}
|
||||
|
||||
if ((placeholder_len = cf_parse_interface(&placeholder, definition)) <= 0) {
|
||||
/* What was not an error during probe definitely is an error during open */
|
||||
snprintf(msg, STATUS_MAX, "Unable to find PCAP file name in definition");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pcapfname = strndup(placeholder, placeholder_len);
|
||||
|
||||
local_pcap->pcapfname = pcapfname;
|
||||
|
||||
if (stat(pcapfname, &sbuf) < 0) {
|
||||
snprintf(msg, STATUS_MAX, "Unable to find pcapfile '%s'", pcapfname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* We don't check for regular file during open, only probe; we don't want to
|
||||
* open a fifo during probe and then cause a glitch, but we could open it during
|
||||
* normal operation */
|
||||
|
||||
local_pcap->pd = pcap_open_offline(pcapfname, errstr);
|
||||
if (strlen(errstr) > 0) {
|
||||
snprintf(msg, STATUS_MAX, "%s", errstr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
local_pcap->datalink_type = pcap_datalink(local_pcap->pd);
|
||||
*dlt = local_pcap->datalink_type;
|
||||
|
||||
/* Kluge a UUID out of the name */
|
||||
snprintf(errstr, PCAP_ERRBUF_SIZE, "%08X-0000-0000-0000-0000%08X",
|
||||
adler32_csum((unsigned char *) "kismet_cap_pcapfile",
|
||||
strlen("kismet_cap_pcapfile")) & 0xFFFFFFFF,
|
||||
adler32_csum((unsigned char *) pcapfname,
|
||||
strlen(pcapfname)) & 0xFFFFFFFF);
|
||||
*uuid = strdup(errstr);
|
||||
|
||||
/* Succesful open with no channel, hop, or chanset data */
|
||||
snprintf(msg, STATUS_MAX, "Opened pcapfile '%s' for playback", pcapfname);
|
||||
|
||||
if ((placeholder_len = cf_find_flag(&placeholder, "realtime", definition)) > 0) {
|
||||
if (strncasecmp(placeholder, "true", placeholder_len) == 0) {
|
||||
snprintf(errstr, PCAP_ERRBUF_SIZE,
|
||||
"Pcapfile '%s' will replay in realtime", pcapfname);
|
||||
cf_send_message(caph, errstr, MSGFLAG_INFO);
|
||||
local_pcap->realtime = 1;
|
||||
}
|
||||
} else if ((placeholder_len = cf_find_flag(&placeholder, "pps", definition)) > 0) {
|
||||
unsigned int pps;
|
||||
if (sscanf(placeholder, "%u", &pps) == 1) {
|
||||
snprintf(errstr, PCAP_ERRBUF_SIZE,
|
||||
"Pcapfile '%s' will throttle to %u packets per second", pcapfname, pps);
|
||||
cf_send_message(caph, errstr,MSGFLAG_INFO);
|
||||
local_pcap->pps_throttle = pps;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void pcap_dispatch_cb(u_char *user, const struct pcap_pkthdr *header,
|
||||
const u_char *data) {
|
||||
kis_capture_handler_t *caph = (kis_capture_handler_t *) user;
|
||||
local_pcap_t *local_pcap = (local_pcap_t *) caph->userdata;
|
||||
int ret;
|
||||
unsigned long delay_usec = 0;
|
||||
|
||||
/* If we're doing 'realtime' playback, delay accordingly based on the
|
||||
* previous packet.
|
||||
*
|
||||
* Because we're in our own thread, we can block as long as we want - this
|
||||
* simulates blocking IO for capturing from hardware, too.
|
||||
*/
|
||||
if (local_pcap->realtime) {
|
||||
if (local_pcap->last_ts.tv_sec == 0 && local_pcap->last_ts.tv_usec == 0) {
|
||||
delay_usec = 0;
|
||||
} else {
|
||||
/* Catch corrupt pcaps w/ inconsistent times */
|
||||
if (header->ts.tv_sec < local_pcap->last_ts.tv_sec) {
|
||||
delay_usec = 0;
|
||||
} else {
|
||||
delay_usec = (header->ts.tv_sec - local_pcap->last_ts.tv_sec) * 1000000L;
|
||||
}
|
||||
|
||||
if (header->ts.tv_usec < local_pcap->last_ts.tv_usec) {
|
||||
delay_usec += (1000000L - local_pcap->last_ts.tv_usec) +
|
||||
header->ts.tv_usec;
|
||||
} else {
|
||||
delay_usec += header->ts.tv_usec - local_pcap->last_ts.tv_usec;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
local_pcap->last_ts.tv_sec = header->ts.tv_sec;
|
||||
local_pcap->last_ts.tv_usec = header->ts.tv_usec;
|
||||
|
||||
if (delay_usec != 0) {
|
||||
usleep(delay_usec);
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're doing 'packet per second' throttling, delay accordingly */
|
||||
if (local_pcap->pps_throttle > 0) {
|
||||
delay_usec = 1000000L / local_pcap->pps_throttle;
|
||||
|
||||
if (delay_usec != 0)
|
||||
usleep(delay_usec);
|
||||
}
|
||||
|
||||
/* Try repeatedly to send the packet; go into a thread wait state if
|
||||
* the write buffer is full & we'll be woken up as soon as it flushes
|
||||
* data out in the main select() loop */
|
||||
while (1) {
|
||||
if ((ret = cf_send_data(caph,
|
||||
NULL, NULL, NULL,
|
||||
header->ts,
|
||||
local_pcap->datalink_type,
|
||||
header->caplen, (uint8_t *) data)) < 0) {
|
||||
pcap_breakloop(local_pcap->pd);
|
||||
cf_send_error(caph, 0, "unable to send DATA frame");
|
||||
cf_handler_spindown(caph);
|
||||
} else if (ret == 0) {
|
||||
/* Go into a wait for the write buffer to get flushed */
|
||||
// fprintf(stderr, "debug - pcapfile - dispatch_cb - no room in write buffer - waiting for it to have more space\n");
|
||||
cf_handler_wait_ringbuffer(caph);
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void capture_thread(kis_capture_handler_t *caph) {
|
||||
local_pcap_t *local_pcap = (local_pcap_t *) caph->userdata;
|
||||
char errstr[PCAP_ERRBUF_SIZE];
|
||||
char *pcap_errstr;
|
||||
|
||||
pcap_loop(local_pcap->pd, -1, pcap_dispatch_cb, (u_char *) caph);
|
||||
|
||||
pcap_errstr = pcap_geterr(local_pcap->pd);
|
||||
|
||||
snprintf(errstr, PCAP_ERRBUF_SIZE, "Pcapfile '%s' closed: %s",
|
||||
local_pcap->pcapfname,
|
||||
strlen(pcap_errstr) == 0 ? "end of pcapfile reached" : pcap_errstr );
|
||||
|
||||
cf_send_message(caph, errstr, MSGFLAG_INFO);
|
||||
|
||||
/* Instead of dying, spin forever in a sleep loop */
|
||||
while (1) {
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
/* cf_handler_spindown(caph); */
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
local_pcap_t local_pcap = {
|
||||
.pd = NULL,
|
||||
.pcapfname = NULL,
|
||||
.datalink_type = -1,
|
||||
.override_dlt = -1,
|
||||
.realtime = 0,
|
||||
.last_ts.tv_sec = 0,
|
||||
.last_ts.tv_usec = 0,
|
||||
.pps_throttle = 0,
|
||||
};
|
||||
|
||||
#if 0
|
||||
/* Remap stderr so we can log debugging to a file */
|
||||
FILE *sterr;
|
||||
sterr = fopen("/tmp/capture_pcapfile.stderr", "a");
|
||||
dup2(fileno(sterr), STDERR_FILENO);
|
||||
#endif
|
||||
|
||||
/* fprintf(stderr, "CAPTURE_PCAPFILE launched on pid %d\n", getpid()); */
|
||||
|
||||
kis_capture_handler_t *caph = cf_handler_init("pcapfile");
|
||||
|
||||
if (caph == NULL) {
|
||||
fprintf(stderr, "FATAL: Could not allocate basic handler data, your system "
|
||||
"is very low on RAM or something is wrong.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set the local data ptr */
|
||||
cf_handler_set_userdata(caph, &local_pcap);
|
||||
|
||||
/* Set the callback for opening a pcapfile */
|
||||
cf_handler_set_open_cb(caph, open_callback);
|
||||
|
||||
/* Set the callback for probing an interface */
|
||||
cf_handler_set_probe_cb(caph, probe_callback);
|
||||
|
||||
/* Set the capture thread */
|
||||
cf_handler_set_capture_cb(caph, capture_thread);
|
||||
|
||||
if (cf_handler_parse_opts(caph, argc, argv) < 1) {
|
||||
cf_print_help(caph, argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Support remote capture by launching the remote loop */
|
||||
cf_handler_remote_capture(caph);
|
||||
|
||||
cf_handler_loop(caph);
|
||||
|
||||
cf_handler_free(caph);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -1,458 +0,0 @@
|
|||
"""
|
||||
rtl_433 Kismet data source
|
||||
|
||||
(c) 2018 Mike Kershaw / Dragorn
|
||||
Licensed under GPL2 or above
|
||||
|
||||
Supports both local usb rtlsdr devices via the rtl_433 binary, remote capture
|
||||
from a usb rtlsdr, and remote capture from a mqtt stream, if paho mqtt is
|
||||
installed.
|
||||
|
||||
Sources are generated as rtl433-XYZ when multiple rtl radios are detected.
|
||||
|
||||
Accepts standard options:
|
||||
channel=freqMHz (in mhz)
|
||||
channel=freqKHz (in khz)
|
||||
channel=freq (in raw hz to rtl_433)
|
||||
|
||||
channels="a,b,c" Pass hopping list to rtl433_bin
|
||||
|
||||
Additionally accepts:
|
||||
ppm_error Passed as -p to rtl_433
|
||||
gain Passed as -g to rtl_433
|
||||
|
||||
mqtt MQTT server
|
||||
mqtt_port MQTT port (default 1883)
|
||||
mqtt_channel MQTT channel (default rtl433)
|
||||
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import ctypes
|
||||
from datetime import datetime
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import uuid
|
||||
|
||||
from . import kismetexternal
|
||||
|
||||
try:
|
||||
import paho.mqtt.client as mqtt
|
||||
has_mqtt = True
|
||||
except ImportError:
|
||||
has_mqtt = False
|
||||
|
||||
class KismetRtl433(object):
|
||||
def __init__(self, mqtt = False):
|
||||
self.mqtt_mode = mqtt
|
||||
|
||||
self.opts = {}
|
||||
|
||||
self.opts['rtlbin'] = 'rtl_433'
|
||||
self.opts['channel'] = "433.920MHz"
|
||||
self.opts['gain'] = None
|
||||
self.opts['device'] = None
|
||||
self.opts['uuid'] = None
|
||||
|
||||
# Thread that runs the RTL popen
|
||||
self.rtl_thread = None
|
||||
# The popen'd RTL binary
|
||||
self.rtl_exec = None
|
||||
|
||||
# Are we killing rtl because we're reconfiguring?
|
||||
self.rtl_reconfigure = False
|
||||
|
||||
# We're usually not remote
|
||||
self.proberet = None
|
||||
|
||||
# Do we have librtl?
|
||||
self.have_librtl = False
|
||||
|
||||
if not self.mqtt_mode:
|
||||
self.driverid = "rtl433"
|
||||
# Use ctypes to load librtlsdr and probe for supported USB devices
|
||||
try:
|
||||
self.rtllib = ctypes.CDLL("librtlsdr.so.0")
|
||||
|
||||
self.rtl_get_device_count = self.rtllib.rtlsdr_get_device_count
|
||||
self.rtl_get_device_name = self.rtllib.rtlsdr_get_device_name
|
||||
self.rtl_get_device_name.argtypes = [ctypes.c_int]
|
||||
self.rtl_get_device_name.restype = ctypes.c_char_p
|
||||
self.rtl_get_usb_strings = self.rtllib.rtlsdr_get_device_usb_strings
|
||||
self.rtl_get_usb_strings.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p]
|
||||
self.have_librtl = True
|
||||
except OSError:
|
||||
self.have_librtl = False
|
||||
else:
|
||||
self.driverid = "rtl433mqtt"
|
||||
|
||||
parser = argparse.ArgumentParser(description='RTL433 to Kismet bridge - Creates a rtl433 data source on a Kismet server and passes JSON-based records from the rtl_433 binary',
|
||||
epilog='Requires the rtl_433 tool (install your distributions package or compile from https://github.com/merbanan/rtl_433)')
|
||||
|
||||
parser.add_argument('--in-fd', action="store", type=int, dest="infd")
|
||||
parser.add_argument('--out-fd', action="store", type=int, dest="outfd")
|
||||
parser.add_argument('--connect', action="store", dest="connect")
|
||||
parser.add_argument("--source", action="store", dest="source")
|
||||
|
||||
self.config = parser.parse_args()
|
||||
|
||||
if not self.config.connect == None and self.config.source == None:
|
||||
print("You must specify a source with --source when connecting to a remote Kismet server")
|
||||
sys.exit(0)
|
||||
|
||||
if not self.config.source == None:
|
||||
(source, options) = kismetexternal.Datasource.parse_definition(self.config.source)
|
||||
|
||||
if source == None:
|
||||
print("Could not parse the --source option; this should be a standard Kismet source definition.")
|
||||
sys.exit(0)
|
||||
|
||||
self.proberet = self.datasource_probesource(source, options)
|
||||
|
||||
if self.proberet == None:
|
||||
print("Could not configure local source {}, check your source options and config.")
|
||||
sys.exit(0)
|
||||
|
||||
if not "success" in self.proberet:
|
||||
print("Could not configure local source {}, check your source options and config.")
|
||||
if "message" in self.proberet:
|
||||
print(self.proberet["message"])
|
||||
sys.exit(0)
|
||||
|
||||
if not self.proberet["success"]:
|
||||
print("Could not configure local source {}, check your source options and config.")
|
||||
if "message" in self.proberet:
|
||||
print(self.proberet["message"].decode('utf-8'))
|
||||
sys.exit(0)
|
||||
|
||||
print("Connecting to remote server {}".format(self.config.connect))
|
||||
|
||||
self.kismet = kismetexternal.Datasource(self.config.infd, self.config.outfd, remote = self.config.connect)
|
||||
|
||||
self.kismet.set_configsource_cb(self.datasource_configure)
|
||||
self.kismet.set_listinterfaces_cb(self.datasource_listinterfaces)
|
||||
self.kismet.set_opensource_cb(self.datasource_opensource)
|
||||
self.kismet.set_probesource_cb(self.datasource_probesource)
|
||||
|
||||
# If we're connecting remote, kick a newsource
|
||||
if self.proberet:
|
||||
print("Registering remote source {} {}".format(self.driverid, self.config.source))
|
||||
self.kismet.send_datasource_newsource(self.config.source, self.driverid, self.proberet['uuid'])
|
||||
|
||||
self.kismet.start()
|
||||
|
||||
def is_running(self):
|
||||
return self.kismet.is_running()
|
||||
|
||||
def get_rtl_usb_info(self, index):
|
||||
# Allocate memory buffers
|
||||
usb_manuf = (ctypes.c_char * 256)()
|
||||
usb_product = (ctypes.c_char * 256)()
|
||||
usb_serial = (ctypes.c_char * 256)()
|
||||
|
||||
# Call the library
|
||||
self.rtl_get_usb_strings(index, usb_manuf, usb_product, usb_serial)
|
||||
|
||||
# If there's a smarter way to do this, patches welcome
|
||||
m = bytearray(usb_manuf)
|
||||
p = bytearray(usb_product)
|
||||
s = bytearray(usb_serial)
|
||||
|
||||
# Return tuple
|
||||
return (m.decode('ascii'), p.decode('ascii'), s.decode('ascii'))
|
||||
|
||||
def check_rtl_bin(self):
|
||||
try:
|
||||
FNULL = open(os.devnull, 'w')
|
||||
r = subprocess.check_call([self.opts['rtlbin'], "--help"], stdout=FNULL, stderr=FNULL)
|
||||
except subprocess.CalledProcessError:
|
||||
return True
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def __rtl_thread(self):
|
||||
""" Internal thread for running the rtl binary """
|
||||
cmd = [ self.opts['rtlbin'], '-F', 'json', '-G' ]
|
||||
|
||||
if self.opts['device'] is not None:
|
||||
cmd.append('-d')
|
||||
cmd.append("{}".format(self.opts['device']))
|
||||
|
||||
if self.opts['gain'] is not None:
|
||||
cmd.append('-g')
|
||||
cmd.append("{}".format(self.opts['gain']))
|
||||
|
||||
if self.opts['channel'] is not None:
|
||||
cmd.append('-f')
|
||||
cmd.append("{}".format(self.opts['channel']))
|
||||
|
||||
seen_any_valid = False
|
||||
failed_once = False
|
||||
|
||||
try:
|
||||
FNULL = open(os.devnull, 'w')
|
||||
self.rtl_exec = subprocess.Popen(cmd, stderr=FNULL, stdout=subprocess.PIPE)
|
||||
|
||||
while True:
|
||||
l = self.rtl_exec.stdout.readline()
|
||||
|
||||
if not self.handle_json(l):
|
||||
raise RuntimeError('could not process response from rtl_433')
|
||||
|
||||
seen_any_valid = True
|
||||
|
||||
|
||||
except Exception as e:
|
||||
# Catch all errors, but don't die if we're reconfiguring rtl; then we need
|
||||
# to relaunch the binary
|
||||
if not self.rtl_reconfigure:
|
||||
self.kismet.send_datasource_error_report(message = "Unable to process output from rtl_433: {}".format(e))
|
||||
finally:
|
||||
if not seen_any_valid and not self.rtl_reconfigure:
|
||||
self.kismet.send_datasource_error_report(message = "An error occurred in rtl_433 and no valid devices were seen; is your USB device plugged in? Try running rtl_433 in a terminal and confirm that it can connect to your device.")
|
||||
self.kismet.spindown()
|
||||
|
||||
self.rtl_exec.kill()
|
||||
|
||||
|
||||
def run_rtl433(self):
|
||||
if self.rtl_thread != None:
|
||||
# Turn on reconfigure mode
|
||||
if self.rtl_exec != None:
|
||||
self.rtl_reconfigure = True
|
||||
self.rtl_exec.kill(9)
|
||||
|
||||
# Let the thread spin down and turn off reconfigure mode
|
||||
self.rtl_thread.join()
|
||||
self.rtl_reconfigure = False
|
||||
|
||||
self.rtl_thread = threading.Thread(target=self.__rtl_thread)
|
||||
self.rtl_thread.daemon = True
|
||||
self.rtl_thread.start()
|
||||
|
||||
def __mqtt_thread(self):
|
||||
self.mq.loop_forever()
|
||||
|
||||
def run_mqtt(self, options):
|
||||
def on_msg(client, user, msg):
|
||||
if not self.handle_json(msg.payload):
|
||||
raise RuntimeError('could not post data')
|
||||
|
||||
opts = options
|
||||
opts.setdefault("mqtt", 'localhost')
|
||||
opts.setdefault("mqtt_port", '1883')
|
||||
opts.setdefault("mqtt_channel", 'rtl433')
|
||||
|
||||
self.mq = mqtt.Client()
|
||||
self.mq.on_message = on_msg
|
||||
self.mq.connect(opts['mqtt'], int(opts['mqtt_port']))
|
||||
self.mq.subscribe(opts['mqtt_channel'])
|
||||
|
||||
self.mq_thread = threading.Thread(target=self.__mqtt_thread)
|
||||
self.mq_thread.daemon = True
|
||||
self.mq_thread.start()
|
||||
|
||||
|
||||
# Implement the listinterfaces callback for the datasource api;
|
||||
def datasource_listinterfaces(self, seqno):
|
||||
interfaces = []
|
||||
|
||||
if not self.check_rtl_bin():
|
||||
self.kismet.send_datasource_interfaces_report(seqno, interfaces)
|
||||
return
|
||||
|
||||
if self.rtllib != None:
|
||||
for i in range(0, self.rtl_get_device_count()):
|
||||
intf = kismetexternal.datasource_pb2.SubInterface()
|
||||
intf.interface = "rtl433-{}".format(i)
|
||||
intf.flags = ""
|
||||
intf.hardware = self.rtl_get_device_name(i)
|
||||
interfaces.append(intf)
|
||||
|
||||
self.kismet.send_datasource_interfaces_report(seqno, interfaces)
|
||||
|
||||
def __get_mqtt_uuid(self, options):
|
||||
opts = options
|
||||
opts.setdefault('mqtt', 'localhost')
|
||||
opts.setdefault('mqtt_port', '1883')
|
||||
opts.setdefault('mqtt_channel', 'kismet')
|
||||
|
||||
mqhash = kismetexternal.Datasource.adler32("{}{}{}".format(opts['mqtt'], opts['mqtt_port'], opts['mqtt_channel']))
|
||||
mqhex = "0000{:02X}".format(mqhash)
|
||||
|
||||
return kismetexternal.Datasource.make_uuid("kismet_cap_sdr_rtl433", mqhex)
|
||||
|
||||
def __get_rtlsdr_uuid(self, intnum):
|
||||
# Get the USB info
|
||||
(manuf, product, serial) = self.get_rtl_usb_info(intnum)
|
||||
|
||||
# Hash the slot, manuf, product, and serial, to get a unique ID for the UUID
|
||||
devicehash = kismetexternal.Datasource.adler32("{}{}{}{}".format(intnum, manuf, product, serial))
|
||||
devicehex = "0000{:02X}".format(devicehash)
|
||||
|
||||
return kismetexternal.Datasource.make_uuid("kismet_cap_sdr_rtl433", devicehex)
|
||||
|
||||
# Implement the probesource callback for the datasource api
|
||||
def datasource_probesource(self, source, options):
|
||||
ret = {}
|
||||
|
||||
# Does the source look like 'rtl433-XYZ'?
|
||||
if not source[:7] == "rtl433-":
|
||||
return None
|
||||
|
||||
if source[7:] == "mqtt":
|
||||
if not 'mqtt' in options:
|
||||
return None
|
||||
if not has_mqtt:
|
||||
return None
|
||||
|
||||
ret['hardware'] = "MQTT"
|
||||
if ('uuid' in options):
|
||||
ret['uuid'] = options['uuid']
|
||||
else:
|
||||
ret['uuid'] = self.__get_mqtt_uuid(options)
|
||||
else:
|
||||
# Do we have librtl?
|
||||
if not self.have_librtl:
|
||||
return None
|
||||
|
||||
if self.mqtt_mode:
|
||||
return None
|
||||
|
||||
if not self.check_rtl_bin():
|
||||
return None
|
||||
|
||||
try:
|
||||
intnum = int(source[7:])
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
if intnum >= self.rtl_get_device_count():
|
||||
return None
|
||||
|
||||
ret['hardware'] = self.rtl_get_device_name(intnum)
|
||||
|
||||
if ('uuid' in options):
|
||||
ret['uuid'] = options['uuid']
|
||||
else:
|
||||
ret['uuid'] = self.__get_rtlsdr_uuid(intnum)
|
||||
|
||||
ret['channel'] = self.opts['channel']
|
||||
ret['channels'] = [self.opts['channel']]
|
||||
ret['success'] = True
|
||||
return ret
|
||||
|
||||
def datasource_opensource(self, source, options):
|
||||
ret = {}
|
||||
|
||||
# Does the source look like 'rtl433-XYZ'?
|
||||
if not source[:7] == "rtl433-":
|
||||
ret['success'] = False
|
||||
ret['message'] = "Could not parse which rtlsdr device to use"
|
||||
return ret
|
||||
|
||||
intnum = -1
|
||||
|
||||
if source[7:] == "mqtt":
|
||||
if not 'mqtt' in options:
|
||||
ret["success"] = False
|
||||
ret["message"] = "MQTT requested, but no mqtt=xyz option in source definition"
|
||||
return ret
|
||||
if not has_mqtt:
|
||||
ret["success"] = False
|
||||
ret["message"] = "MQTT requested, but the python paho mqtt package is not installed"
|
||||
return ret
|
||||
|
||||
ret['hardware'] = "MQTT"
|
||||
if ('uuid' in options):
|
||||
ret['uuid'] = options['uuid']
|
||||
else:
|
||||
ret['uuid'] = self.__get_mqtt_uuid(options)
|
||||
|
||||
self.mqtt_mode = True
|
||||
else:
|
||||
if not self.have_librtl:
|
||||
ret['success'] = False
|
||||
ret['message'] = "could not find librtlsdr, unable to configure rtlsdr interfaces"
|
||||
return ret
|
||||
|
||||
try:
|
||||
intnum = int(source[7:])
|
||||
except ValueError:
|
||||
ret['success'] = False
|
||||
ret['message'] = "Could not parse rtl device"
|
||||
return ret
|
||||
|
||||
if intnum >= self.rtl_get_device_count():
|
||||
ret['success'] = False
|
||||
ret['message'] = "Could not find rtl-sdr device {}".format(intnum)
|
||||
return ret
|
||||
|
||||
if 'channel' in options:
|
||||
self.opts['channel'] = options['channel']
|
||||
|
||||
ret['hardware'] = self.rtl_get_device_name(intnum)
|
||||
if ('uuid' in options):
|
||||
ret['uuid'] = options['uuid']
|
||||
else:
|
||||
ret['uuid'] = self.__get_rtlsdr_uuid(intnum)
|
||||
|
||||
self.opts['device'] = intnum
|
||||
|
||||
self.mqtt_mode = False
|
||||
|
||||
if not self.mqtt_mode:
|
||||
if not self.check_rtl_bin():
|
||||
ret['success'] = False
|
||||
ret['message'] = "Could not find rtl_433 binary; make sure you've installed rtl_433, check the Kismet README for more information."
|
||||
return
|
||||
|
||||
ret['success'] = True
|
||||
|
||||
if self.mqtt_mode:
|
||||
self.run_mqtt(options)
|
||||
else:
|
||||
self.run_rtl433()
|
||||
|
||||
return ret
|
||||
|
||||
def datasource_configure(self, seqno, config):
|
||||
#print(config)
|
||||
|
||||
return {"success": True}
|
||||
|
||||
def handle_json(self, injson):
|
||||
try:
|
||||
j = json.loads(injson)
|
||||
r = json.dumps(j)
|
||||
|
||||
report = kismetexternal.datasource_pb2.SubJson()
|
||||
|
||||
dt = datetime.now()
|
||||
report.time_sec = int(time.mktime(dt.timetuple()))
|
||||
report.time_usec = int(dt.microsecond)
|
||||
|
||||
report.type = "RTL433"
|
||||
report.json = r
|
||||
|
||||
# print("python sending json report", r);
|
||||
|
||||
self.kismet.send_datasource_data_report(full_json=report)
|
||||
except ValueError as e:
|
||||
print(e)
|
||||
self.kismet.send_datasource_error_report(message = "Could not parse JSON output of rtl_433")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(e)
|
||||
self.kismet.send_datasource_error_report(message = "Could not process output of rtl_433")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,21 +0,0 @@
|
|||
include ../Makefile.inc
|
||||
|
||||
MONITOR_BIN = kismet_cap_sdr_rtl433
|
||||
MQTTMONITOR_BIN = kismet_cap_sdr_rtl433_mqtt
|
||||
|
||||
all:
|
||||
( cd KismetCaptureRtl433/kismetexternal; \
|
||||
$(PROTOCBIN) -I ../../../protobuf_definitions --python_out=. ../../../protobuf_definitions/*.proto; \
|
||||
sed -i -E 's/^import.*_pb2/from . \0/' *_pb2.py ; \
|
||||
)
|
||||
$(PYTHON2) ./setup.py bdist
|
||||
|
||||
install:
|
||||
$(PYTHON2) ./setup.py install
|
||||
# These are now part of the setup.py install
|
||||
# $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) $(MONITOR_BIN) $(BIN)/$(MONITOR_BIN)
|
||||
# $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) $(MQTTMONITOR_BIN) $(BIN)/$(MQTTMONITOR_BIN)
|
||||
|
||||
clean:
|
||||
@-$(PYTHON2) ./setup.py clean
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
Kismet RTL433 Support
|
||||
|
||||
- UNDER DEVELOPMENT -
|
||||
|
||||
The rtl-sdr support in Kismet is under heavy development, not all
|
||||
features are complete at this time (alternate frequencies,
|
||||
channel hopping, and some other functionality are still being
|
||||
completed).
|
||||
|
||||
- RTL-SDR -
|
||||
|
||||
The Kismet rtl_433 SDR capture requires a RTL-SDR USB device; you
|
||||
can learn more about these on the main RTL-SDR website:
|
||||
https://www.rtl-sdr.com
|
||||
|
||||
The RTL-SDR is typically an extremely low-cost USB device which
|
||||
can perform limited raw radio capture. While often *extremely*
|
||||
limited, the RTL-SDR is still capable of a surprising amount of
|
||||
useful capture.
|
||||
|
||||
To use the RTL SDR capture device, you will need a rtlsdr;
|
||||
your Wi-Fi card cannot receive the signal.
|
||||
|
||||
- RTL_433 -
|
||||
|
||||
Kismet requires the rtl_433 tool be installed. The rtl_433
|
||||
tool can typically be installed as package by your distribution,
|
||||
compiled as part of the pybombs system, or installed manually
|
||||
from the source at:
|
||||
https://github.com/merbanan/rtl_433
|
||||
|
||||
The rtl_433 tool uses the RTL-SDR hardware to sniff for broadcasts
|
||||
from a wide variety of sensors found on the 433MHz ISM spectrum
|
||||
(one of the segments of the radio bands which is reserved for
|
||||
non-licensed applications, similar to the bands Wi-Fi and
|
||||
Bluetooth live in).
|
||||
|
||||
These sensors include a variety of temperature and humidity
|
||||
sensors, power and water meter systems, radio-controlled power
|
||||
switches, weather stations, tire pressure monitoring systems,
|
||||
and more.
|
||||
|
||||
- CONFIGURING RTL_433 -
|
||||
|
||||
The only configuration necessary to configure rtl_433 is to make
|
||||
sure that your user has access to the rtlsdr USB device.
|
||||
This is usually accomplished by installing the udev rules which
|
||||
accompany librtlsdr.
|
||||
|
||||
Typically the group `plugdev` is given access; make sure the
|
||||
user you plan to run Kismet as is in that group.
|
||||
|
||||
For more information, check the documentation that came with
|
||||
librtlsdr or the rtlsdr website:
|
||||
https://rtl-sdr.com
|
||||
|
||||
- CONFIGURING KISMET -
|
||||
|
||||
The Kismet capture driver is implemented as a Python datasource;
|
||||
you will need the Kismet-related Python modules from the
|
||||
python_modules/ directory of Kismet (which will be installed
|
||||
automatically in most cases).
|
||||
|
||||
rtlsdr hardware will be automatically detected and shown in the
|
||||
Datasources window, or it can be configured as 'rtl433-X',
|
||||
where 'X' is the radio you wish to use. If you have only one
|
||||
radio, this will always be zero; for instance:
|
||||
|
||||
source=rtl433-0:name=some_sdr
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
"""
|
||||
rtl_433 Kismet data source
|
||||
|
||||
Implements a rtl_433 datasource for Kismet, using the
|
||||
KismetCaptureRtl433 Python module
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
||||
try:
|
||||
import KismetCaptureRtl433
|
||||
except ImportError as e:
|
||||
print("Could not import the KismetCaptureRtl433 Python code; you are likely missing")
|
||||
print("a Python dependency or the KismetCaptureRtl433 python module is not installed:")
|
||||
print(e)
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.tracebacklimit = 0
|
||||
|
||||
rtl = KismetCaptureRtl433.KismetRtl433()
|
||||
|
||||
# Go into sleep mode
|
||||
while rtl.is_running():
|
||||
time.sleep(1)
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
"""
|
||||
rtl_433 Kismet data source
|
||||
|
||||
Implements a rtl_433 datasource for Kismet, using the
|
||||
KismetCaptureRtl433 Python module
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
||||
try:
|
||||
import KismetCaptureRtl433
|
||||
except ImportError as e:
|
||||
print("Could not import the KismetCaptureRtl433 Python code; you are likely missing")
|
||||
print("a Python dependency or the KismetCaptureRtl433 python module is not installed:")
|
||||
print(e)
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.tracebacklimit = 0
|
||||
|
||||
rtl = KismetCaptureRtl433.KismetRtl433(mqtt=True)
|
||||
|
||||
# Go into sleep mode
|
||||
while rtl.is_running():
|
||||
time.sleep(1)
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(name='KismetCaptureRtl433',
|
||||
version='2018.0.0',
|
||||
description='Kismet rtl_433 datasource',
|
||||
author='Mike Kershaw / Dragorn',
|
||||
author_email='dragorn@kismetwireless.net',
|
||||
url='https://www.kismetwireless.net/',
|
||||
install_requires=['protobuf'],
|
||||
packages=find_packages(),
|
||||
scripts=['kismet_cap_sdr_rtl433', 'kismet_cap_sdr_rtl433_mqtt'],
|
||||
)
|
||||
|
||||
|
|
@ -1,668 +0,0 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
"""
|
||||
rtladsb Kismet data source
|
||||
|
||||
Supports both local usb rtlsdr devices via the rtladsb binary, remote capture
|
||||
from a usb rtlsdr, and remote capture from a mqtt stream, if paho mqtt is
|
||||
installed.
|
||||
|
||||
Sources are generated as rtladsb-XYZ when multiple rtl radios are detected.
|
||||
|
||||
Accepts standard options:
|
||||
channel=freqMHz (in mhz)
|
||||
channel=freqKHz (in khz)
|
||||
channel=freq (in raw hz to rtladsb)
|
||||
|
||||
channels="a,b,c" Pass hopping list to rtladsb_bin
|
||||
|
||||
Additionally accepts:
|
||||
ppm_error Passed as -p to rtladsb
|
||||
gain Passed as -g to rtladsb
|
||||
|
||||
mqtt MQTT server
|
||||
mqtt_port MQTT port (default 1883)
|
||||
mqtt_channel MQTT channel (default rtladsb)
|
||||
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
import ctypes
|
||||
from datetime import datetime
|
||||
import json
|
||||
import math
|
||||
|
||||
try:
|
||||
import numpy as np
|
||||
except ImportError as e:
|
||||
raise ImportError("KismetRtladsb requires numpy!")
|
||||
|
||||
import os
|
||||
import pkgutil
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import uuid
|
||||
|
||||
### THE NEXT CODE BLOCK IS FROM THE WORK OF myModeS AVAILABLE AT ###
|
||||
### https://pypi.org/project/pyModeS/ ###
|
||||
### IT IS INCLUDED HERE IN THIS VERSION STRIPPED DOWN AND MODIFIED ###
|
||||
### DUE TO UPSTEAM CHANGES IN THE ORIGINAL CODEBASE THAT ARENT NEEDED ###
|
||||
def hex2bin(hexstr):
|
||||
"""Convert a hexdecimal string to binary string, with zero fillings. """
|
||||
num_of_bits = len(hexstr) * 4
|
||||
binstr = bin(int(hexstr, 16))[2:].zfill(int(num_of_bits))
|
||||
return binstr
|
||||
|
||||
def bin2int(binstr):
|
||||
"""Convert a binary string to integer. """
|
||||
return int(binstr, 2)
|
||||
|
||||
def hex2int(hexstr):
|
||||
"""Convert a hexdecimal string to integer. """
|
||||
return int(hexstr, 16)
|
||||
|
||||
def bin2np(binstr):
|
||||
"""Convert a binary string to numpy array. """
|
||||
return np.array([int(i) for i in binstr])
|
||||
|
||||
def np2bin(npbin):
|
||||
"""Convert a binary numpy array to string. """
|
||||
return np.array2string(npbin, separator='')[1:-1]
|
||||
|
||||
def df(msg):
|
||||
"""Decode Downlink Format vaule, bits 1 to 5."""
|
||||
msgbin = hex2bin(msg)
|
||||
return min( bin2int(msgbin[0:5]) , 24 )
|
||||
|
||||
def crc(msg, encode=False):
|
||||
"""Mode-S Cyclic Redundancy Check
|
||||
Detect if bit error occurs in the Mode-S message
|
||||
Args:
|
||||
msg (string): 28 bytes hexadecimal message string
|
||||
encode (bool): True to encode the date only and return the checksum
|
||||
Returns:
|
||||
string: message checksum, or partity bits (encoder)
|
||||
"""
|
||||
|
||||
# the polynominal generattor code for CRC [1111111111111010000001001]
|
||||
generator = np.array([1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,1,0,0,1])
|
||||
ng = len(generator)
|
||||
|
||||
msgnpbin = bin2np(hex2bin(msg))
|
||||
|
||||
if encode:
|
||||
msgnpbin[-24:] = [0] * 24
|
||||
|
||||
# loop all bits, except last 24 piraty bits
|
||||
for i in range(len(msgnpbin)-24):
|
||||
if msgnpbin[i] == 0:
|
||||
continue
|
||||
|
||||
# perform XOR, when 1
|
||||
msgnpbin[i:i+ng] = np.bitwise_xor(msgnpbin[i:i+ng], generator)
|
||||
|
||||
# last 24 bits
|
||||
reminder = np2bin(msgnpbin[-24:])
|
||||
return reminder
|
||||
|
||||
def icao(msg):
|
||||
"""Calculate the ICAO address from an Mode-S message
|
||||
with DF4, DF5, DF20, DF21
|
||||
Args:
|
||||
msg (String): 28 bytes hexadecimal message string
|
||||
Returns:
|
||||
String: ICAO address in 6 bytes hexadecimal string
|
||||
"""
|
||||
DF = df(msg)
|
||||
|
||||
if DF in (11, 17, 18):
|
||||
addr = msg[2:8]
|
||||
elif DF in (0, 4, 5, 16, 20, 21):
|
||||
c0 = bin2int(crc(msg, encode=True))
|
||||
c1 = hex2int(msg[-6:])
|
||||
addr = '%06X' % (c0 ^ c1)
|
||||
else:
|
||||
addr = None
|
||||
|
||||
return addr
|
||||
|
||||
def typecode(msg):
|
||||
"""Type code of ADS-B message
|
||||
Args:
|
||||
msg (string): 28 bytes hexadecimal message string
|
||||
Returns:
|
||||
int: type code number
|
||||
"""
|
||||
if df(msg) not in (17, 18):
|
||||
return None
|
||||
|
||||
msgbin = hex2bin(msg)
|
||||
return bin2int(msgbin[32:37])
|
||||
|
||||
def data(msg):
|
||||
"""Return the data frame in the message, bytes 9 to 22"""
|
||||
return msg[8:-6]
|
||||
|
||||
def airborne_velocity(msg):
|
||||
"""Calculate the speed, track (or heading), and vertical rate
|
||||
|
||||
Args:
|
||||
msg (string): 28 bytes hexadecimal message string
|
||||
|
||||
Returns:
|
||||
(int, float, int, string): speed (kt), ground track or heading (degree),
|
||||
rate of climb/descend (ft/min), and speed type
|
||||
('GS' for ground speed, 'AS' for airspeed)
|
||||
"""
|
||||
|
||||
if typecode(msg) != 19:
|
||||
raise RuntimeError("%s: Not a airborne velocity message, expecting TC=19" % msg)
|
||||
|
||||
msgbin = hex2bin(msg)
|
||||
|
||||
subtype = bin2int(msgbin[37:40])
|
||||
|
||||
if bin2int(msgbin[46:56]) == 0 or bin2int(msgbin[57:67]) == 0:
|
||||
return None
|
||||
|
||||
if subtype in (1, 2):
|
||||
v_ew_sign = -1 if int(msgbin[45]) else 1
|
||||
v_ew = bin2int(msgbin[46:56]) - 1 # east-west velocity
|
||||
|
||||
v_ns_sign = -1 if int(msgbin[56]) else 1
|
||||
v_ns = bin2int(msgbin[57:67]) - 1 # north-south velocity
|
||||
|
||||
|
||||
v_we = v_ew_sign * v_ew
|
||||
v_sn = v_ns_sign * v_ns
|
||||
|
||||
spd = math.sqrt(v_sn*v_sn + v_we*v_we) # unit in kts
|
||||
|
||||
trk = math.atan2(v_we, v_sn)
|
||||
trk = math.degrees(trk) # convert to degrees
|
||||
trk = trk if trk >= 0 else trk + 360 # no negative val
|
||||
|
||||
tag = 'GS'
|
||||
trk_or_hdg = trk
|
||||
|
||||
else:
|
||||
hdg = bin2int(msgbin[46:56]) / 1024.0 * 360.0
|
||||
spd = bin2int(msgbin[57:67])
|
||||
|
||||
tag = 'AS'
|
||||
trk_or_hdg = hdg
|
||||
|
||||
vr_sign = -1 if int(msgbin[68]) else 1
|
||||
vr = (bin2int(msgbin[69:78]) - 1) * 64 # vertical rate, fpm
|
||||
rocd = vr_sign * vr
|
||||
|
||||
return int(spd), round(trk_or_hdg, 1), int(rocd), tag
|
||||
|
||||
def callsign(msg):
|
||||
"""Aircraft callsign
|
||||
|
||||
Args:
|
||||
msg (string): 28 bytes hexadecimal message string
|
||||
|
||||
Returns:
|
||||
string: callsign
|
||||
"""
|
||||
|
||||
if typecode(msg) < 1 or typecode(msg) > 4:
|
||||
raise RuntimeError("%s: Not a identification message" % msg)
|
||||
|
||||
chars = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ#####_###############0123456789######'
|
||||
msgbin = hex2bin(msg)
|
||||
csbin = msgbin[40:96]
|
||||
|
||||
cs = ''
|
||||
cs += chars[bin2int(csbin[0:6])]
|
||||
cs += chars[bin2int(csbin[6:12])]
|
||||
cs += chars[bin2int(csbin[12:18])]
|
||||
cs += chars[bin2int(csbin[18:24])]
|
||||
cs += chars[bin2int(csbin[24:30])]
|
||||
cs += chars[bin2int(csbin[30:36])]
|
||||
cs += chars[bin2int(csbin[36:42])]
|
||||
cs += chars[bin2int(csbin[42:48])]
|
||||
|
||||
# clean string, remove spaces and marks, if any.
|
||||
# cs = cs.replace('_', '')
|
||||
cs = cs.replace('#', '')
|
||||
return cs
|
||||
|
||||
### END BLOCK ###
|
||||
|
||||
from . import kismetexternal
|
||||
|
||||
try:
|
||||
import paho.mqtt.client as mqtt
|
||||
has_mqtt = True
|
||||
except ImportError:
|
||||
has_mqtt = False
|
||||
|
||||
class KismetRtladsb(object):
|
||||
def __init__(self, mqtt = False):
|
||||
self.mqtt_mode = mqtt
|
||||
|
||||
self.opts = {}
|
||||
|
||||
self.opts['rtlbin'] = 'rtl_adsb'
|
||||
self.opts['channel'] = "1090.000MHz"
|
||||
self.opts['gain'] = None
|
||||
self.opts['device'] = None
|
||||
|
||||
# Thread that runs the RTL popen
|
||||
self.rtl_thread = None
|
||||
# The popen'd RTL binary
|
||||
self.rtl_exec = None
|
||||
|
||||
# Are we killing rtl because we're reconfiguring?
|
||||
self.rtl_reconfigure = False
|
||||
|
||||
# We're usually not remote
|
||||
self.proberet = None
|
||||
|
||||
# Do we have librtl?
|
||||
self.have_librtl = False
|
||||
|
||||
if not self.mqtt_mode:
|
||||
self.driverid = "rtladsb"
|
||||
# Use ctypes to load librtlsdr and probe for supported USB devices
|
||||
try:
|
||||
self.rtllib = ctypes.CDLL("librtlsdr.so.0")
|
||||
|
||||
self.rtl_get_device_count = self.rtllib.rtlsdr_get_device_count
|
||||
self.rtl_get_device_name = self.rtllib.rtlsdr_get_device_name
|
||||
self.rtl_get_device_name.argtypes = [ctypes.c_int]
|
||||
self.rtl_get_device_name.restype = ctypes.c_char_p
|
||||
self.rtl_get_usb_strings = self.rtllib.rtlsdr_get_device_usb_strings
|
||||
self.rtl_get_usb_strings.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p]
|
||||
self.have_librtl = True
|
||||
except OSError:
|
||||
self.have_librtl = False
|
||||
else:
|
||||
self.driverid = "rtladsbmqtt"
|
||||
|
||||
parser = argparse.ArgumentParser(description='RTLadsb to Kismet bridge - Creates a rtladsb data source on a Kismet server and passes JSON-based records from the rtladsb binary',
|
||||
epilog='Requires the rtladsb tool (install your distributions package or compile from https://github.com/bemasher/rtladsb)')
|
||||
|
||||
parser.add_argument('--in-fd', action="store", type=int, dest="infd")
|
||||
parser.add_argument('--out-fd', action="store", type=int, dest="outfd")
|
||||
parser.add_argument('--connect', action="store", dest="connect")
|
||||
parser.add_argument("--source", action="store", dest="source")
|
||||
|
||||
self.config = parser.parse_args()
|
||||
|
||||
if not self.config.connect == None and self.config.source == None:
|
||||
print("You must specify a source with --source when connecting to a remote Kismet server")
|
||||
sys.exit(0)
|
||||
|
||||
if not self.config.source == None:
|
||||
(source, options) = kismetexternal.Datasource.parse_definition(self.config.source)
|
||||
|
||||
if source == None:
|
||||
print("Could not parse the --source option; this should be a standard Kismet source definition.")
|
||||
sys.exit(0)
|
||||
|
||||
self.proberet = self.datasource_probesource(source, options)
|
||||
|
||||
if self.proberet == None:
|
||||
print("Could not configure local source {}, check your source options and config.")
|
||||
sys.exit(0)
|
||||
|
||||
if not "success" in self.proberet:
|
||||
print("Could not configure local source {}, check your source options and config.")
|
||||
if "message" in self.proberet:
|
||||
print(self.proberet["message"])
|
||||
sys.exit(0)
|
||||
|
||||
if not self.proberet["success"]:
|
||||
print("Could not configure local source {}, check your source options and config.")
|
||||
if "message" in self.proberet:
|
||||
print(self.proberet["message"])
|
||||
sys.exit(0)
|
||||
|
||||
print("Connecting to remote server {}".format(self.config.connect))
|
||||
|
||||
self.csv_data = pkgutil.get_data('KismetCaptureRtladsb', 'data/aircraft_db.csv')
|
||||
self.csv_file = csv.reader(self.csv_data.splitlines(), delimiter=",")
|
||||
self.airplanes = []
|
||||
|
||||
for row in self.csv_file:
|
||||
self.airplanes.append(row)
|
||||
|
||||
self.kismet = kismetexternal.Datasource(self.config.infd, self.config.outfd, remote = self.config.connect)
|
||||
|
||||
self.kismet.set_configsource_cb(self.datasource_configure)
|
||||
self.kismet.set_listinterfaces_cb(self.datasource_listinterfaces)
|
||||
self.kismet.set_opensource_cb(self.datasource_opensource)
|
||||
self.kismet.set_probesource_cb(self.datasource_probesource)
|
||||
|
||||
# If we're connecting remote, kick a newsource
|
||||
if self.proberet:
|
||||
print("Registering remote source {} {}".format(self.driverid, self.config.source))
|
||||
self.kismet.send_datasource_newsource(self.config.source, self.driverid, self.proberet['uuid'])
|
||||
|
||||
self.kismet.start()
|
||||
|
||||
def is_running(self):
|
||||
return self.kismet.is_running()
|
||||
|
||||
def get_rtl_usb_info(self, index):
|
||||
# Allocate memory buffers
|
||||
usb_manuf = (ctypes.c_char * 256)()
|
||||
usb_product = (ctypes.c_char * 256)()
|
||||
usb_serial = (ctypes.c_char * 256)()
|
||||
|
||||
# Call the library
|
||||
self.rtl_get_usb_strings(index, usb_manuf, usb_product, usb_serial)
|
||||
|
||||
# If there's a smarter way to do this, patches welcome
|
||||
m = bytearray(usb_manuf)
|
||||
p = bytearray(usb_product)
|
||||
s = bytearray(usb_serial)
|
||||
|
||||
# Return tuple
|
||||
return (m.decode('ascii'), p.decode('ascii'), s.decode('ascii'))
|
||||
|
||||
def check_rtl_bin(self):
|
||||
try:
|
||||
FNULL = open(os.devnull, 'w')
|
||||
r = subprocess.check_call([self.opts['rtlbin'], "--help"], stdout=FNULL, stderr=FNULL)
|
||||
except subprocess.CalledProcessError:
|
||||
return True
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def __rtl_thread(self):
|
||||
""" Internal thread for running the rtl binary """
|
||||
cmd = [ self.opts['rtlbin'] ]
|
||||
|
||||
if self.opts['device'] is not None:
|
||||
cmd.append('-d')
|
||||
cmd.append("{}".format(self.opts['device']))
|
||||
|
||||
if self.opts['gain'] is not None:
|
||||
cmd.append('-g')
|
||||
cmd.append("{}".format(self.opts['gain']))
|
||||
|
||||
seen_any_valid = False
|
||||
failed_once = False
|
||||
|
||||
try:
|
||||
FNULL = open(os.devnull, 'w')
|
||||
self.rtl_exec = subprocess.Popen(cmd, stderr=FNULL, stdout=subprocess.PIPE)
|
||||
|
||||
while True:
|
||||
hex_data = self.rtl_exec.stdout.readline().decode('ascii').strip()[1:-1]
|
||||
if crc(hex_data) == "000000000000000000000000":
|
||||
for row in self.airplanes:
|
||||
if hex_data[2:8] == row[0]:
|
||||
msg = { "icao": row[0] , "regid": row[1] , "mdl": row[2] , "type": row[3] , "operator": row[4] }
|
||||
if 1 <= typecode(hex_data) <= 4:
|
||||
msg = { "icao": hex_data[2:8], "callsign": callsign(hex_data) }
|
||||
if 5 <= typecode(hex_data) <= 8:
|
||||
msg = { "icao": hex_data[2:8], "altitude": altitude(hex_data) }
|
||||
if typecode(hex_data) == 19:
|
||||
airborneInfo = airborne_velocity(hex_data)
|
||||
msg = { "icao": hex_data[2:8], "speed": airborneInfo[0], "heading": airborneInfo[1], "altitude": airborneInfo[2], "GSAS": airborneInfo[3] }
|
||||
l = json.dumps(msg)
|
||||
|
||||
if not self.handle_json(l):
|
||||
raise RuntimeError('could not process response from rtladsb')
|
||||
|
||||
seen_any_valid = True
|
||||
|
||||
|
||||
except Exception as e:
|
||||
# Catch all errors, but don't die if we're reconfiguring rtl; then we need
|
||||
# to relaunch the binary
|
||||
if not self.rtl_reconfigure:
|
||||
self.kismet.send_datasource_error_report(message = "Unable to process output from rtladsb: {}".format(e))
|
||||
finally:
|
||||
if not seen_any_valid and not self.rtl_reconfigure:
|
||||
self.kismet.send_datasource_error_report(message = "An error occurred in rtladsb and no valid devices were seen; is your USB device plugged in? Try running rtladsb in a terminal and confirm that it can connect to your device.")
|
||||
self.kismet.spindown()
|
||||
|
||||
self.rtl_exec.kill()
|
||||
|
||||
|
||||
def run_rtladsb(self):
|
||||
if self.rtl_thread != None:
|
||||
# Turn on reconfigure mode
|
||||
if self.rtl_exec != None:
|
||||
self.rtl_reconfigure = True
|
||||
self.rtl_exec.kill(9)
|
||||
|
||||
# Let the thread spin down and turn off reconfigure mode
|
||||
self.rtl_thread.join()
|
||||
self.rtl_reconfigure = False
|
||||
|
||||
self.rtl_thread = threading.Thread(target=self.__rtl_thread)
|
||||
self.rtl_thread.daemon = True
|
||||
self.rtl_thread.start()
|
||||
|
||||
def __mqtt_thread(self):
|
||||
self.mq.loop_forever()
|
||||
|
||||
def run_mqtt(self, options):
|
||||
def on_msg(client, user, msg):
|
||||
if not self.handle_json(msg.payload):
|
||||
raise RuntimeError('could not post data')
|
||||
|
||||
opts = options
|
||||
opts.setdefault("mqtt", 'localhost')
|
||||
opts.setdefault("mqtt_port", '1883')
|
||||
opts.setdefault("mqtt_channel", 'rtladsb')
|
||||
|
||||
self.mq = mqtt.Client()
|
||||
self.mq.on_message = on_msg
|
||||
self.mq.connect(opts['mqtt'], int(opts['mqtt_port']))
|
||||
self.mq.subscribe(opts['mqtt_channel'])
|
||||
|
||||
self.mq_thread = threading.Thread(target=self.__mqtt_thread)
|
||||
self.mq_thread.daemon = True
|
||||
self.mq_thread.start()
|
||||
|
||||
|
||||
# Implement the listinterfaces callback for the datasource api;
|
||||
def datasource_listinterfaces(self, seqno):
|
||||
interfaces = []
|
||||
|
||||
if not self.check_rtl_bin():
|
||||
self.kismet.send_datasource_interfaces_report(seqno, interfaces)
|
||||
return
|
||||
|
||||
if self.rtllib != None:
|
||||
for i in range(0, self.rtl_get_device_count()):
|
||||
intf = kismetexternal.datasource_pb2.SubInterface()
|
||||
intf.interface = "rtladsb-{}".format(i)
|
||||
intf.flags = ""
|
||||
intf.hardware = self.rtl_get_device_name(i)
|
||||
interfaces.append(intf)
|
||||
|
||||
self.kismet.send_datasource_interfaces_report(seqno, interfaces)
|
||||
|
||||
def __get_mqtt_uuid(self, options):
|
||||
opts = options
|
||||
opts.setdefault('mqtt', 'localhost')
|
||||
opts.setdefault('mqtt_port', '1883')
|
||||
opts.setdefault('mqtt_channel', 'kismet')
|
||||
|
||||
mqhash = kismetexternal.Datasource.adler32("{}{}{}".format(opts['mqtt'], opts['mqtt_port'], opts['mqtt_channel']))
|
||||
mqhex = "0000{:02X}".format(mqhash)
|
||||
|
||||
return kismetexternal.Datasource.make_uuid("kismet_cap_sdr_rtladsb", mqhex)
|
||||
|
||||
def __get_rtlsdr_uuid(self, intnum):
|
||||
# Get the USB info
|
||||
(manuf, product, serial) = self.get_rtl_usb_info(intnum)
|
||||
|
||||
# Hash the slot, manuf, product, and serial, to get a unique ID for the UUID
|
||||
devicehash = kismetexternal.Datasource.adler32("{}{}{}{}".format(intnum, manuf, product, serial))
|
||||
devicehex = "0000{:02X}".format(devicehash)
|
||||
|
||||
return kismetexternal.Datasource.make_uuid("kismet_cap_sdr_rtladsb", devicehex)
|
||||
|
||||
# Implement the probesource callback for the datasource api
|
||||
def datasource_probesource(self, source, options):
|
||||
ret = {}
|
||||
|
||||
# Does the source look like 'rtladsb-XYZ'?
|
||||
if not source[:8] == "rtladsb-":
|
||||
return None
|
||||
|
||||
if source[9:] == "mqtt":
|
||||
if not 'mqtt' in options:
|
||||
return None
|
||||
if not has_mqtt:
|
||||
return None
|
||||
|
||||
ret['hardware'] = "MQTT"
|
||||
if ('uuid' in options):
|
||||
ret['uuid'] = options['uuid']
|
||||
else:
|
||||
ret['uuid'] = self.__get_mqtt_uuid(options)
|
||||
else:
|
||||
# Do we have librtl?
|
||||
if not self.have_librtl:
|
||||
return None
|
||||
|
||||
if self.mqtt_mode:
|
||||
return None
|
||||
|
||||
if not self.check_rtl_bin():
|
||||
return None
|
||||
|
||||
try:
|
||||
intnum = int(source[8:])
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
if intnum >= self.rtl_get_device_count():
|
||||
return None
|
||||
|
||||
ret['hardware'] = self.rtl_get_device_name(intnum)
|
||||
if ('uuid' in options):
|
||||
ret['uuid'] = options['uuid']
|
||||
else:
|
||||
ret['uuid'] = self.__get_rtlsdr_uuid(intnum)
|
||||
|
||||
ret['channel'] = self.opts['channel']
|
||||
ret['channels'] = [self.opts['channel']]
|
||||
ret['success'] = True
|
||||
return ret
|
||||
|
||||
def datasource_opensource(self, source, options):
|
||||
ret = {}
|
||||
|
||||
# Does the source look like 'rtladsb-XYZ'?
|
||||
if not source[:8] == "rtladsb-":
|
||||
ret["success"] = False
|
||||
ret["message"] = "Could not parse which rtlsdr device to use"
|
||||
return ret
|
||||
|
||||
intnum = -1
|
||||
|
||||
if source[8:] == "mqtt":
|
||||
if not 'mqtt' in options:
|
||||
ret["success"] = False
|
||||
ret["message"] = "MQTT requested, but no mqtt=xyz option in source definition"
|
||||
return ret
|
||||
if not has_mqtt:
|
||||
ret["success"] = False
|
||||
ret["message"] = "MQTT requested, but the python paho mqtt package is not installed"
|
||||
return ret
|
||||
|
||||
ret['hardware'] = "MQTT"
|
||||
if ('uuid' in options):
|
||||
ret['uuid'] = options['uuid']
|
||||
else:
|
||||
ret['uuid'] = self.__get_mqtt_uuid(options)
|
||||
|
||||
self.mqtt_mode = True
|
||||
else:
|
||||
if not self.have_librtl:
|
||||
ret["success"] = False
|
||||
ret["message"] = "could not find librtlsdr, unable to configure rtlsdr interfaces"
|
||||
return ret
|
||||
|
||||
try:
|
||||
intnum = int(source[8:])
|
||||
except ValueError:
|
||||
ret["success"] = False
|
||||
ret["message"] = "Could not parse rtl device"
|
||||
return ret
|
||||
|
||||
if intnum >= self.rtl_get_device_count():
|
||||
ret["success"] = False
|
||||
ret["message"] = "Could not find rtl-sdr device {}".format(intnum)
|
||||
return ret
|
||||
|
||||
if 'channel' in options:
|
||||
self.opts['channel'] = options['channel']
|
||||
|
||||
ret['hardware'] = self.rtl_get_device_name(intnum)
|
||||
if ('uuid' in options):
|
||||
ret['uuid'] = options['uuid']
|
||||
else:
|
||||
ret['uuid'] = self.__get_rtlsdr_uuid(intnum)
|
||||
|
||||
self.opts['device'] = intnum
|
||||
|
||||
self.mqtt_mode = False
|
||||
|
||||
if not self.mqtt_mode:
|
||||
if not self.check_rtl_bin():
|
||||
ret['success'] = False
|
||||
ret['message'] = "Could not find rtladsb binary; make sure you've installed rtladsb, check the Kismet README for more information."
|
||||
return
|
||||
|
||||
ret['success'] = True
|
||||
|
||||
if self.mqtt_mode:
|
||||
self.run_mqtt(options)
|
||||
else:
|
||||
self.run_rtladsb()
|
||||
|
||||
return ret
|
||||
|
||||
def datasource_configure(self, seqno, config):
|
||||
#print(config)
|
||||
|
||||
return {"success": True}
|
||||
|
||||
def handle_json(self, injson):
|
||||
try:
|
||||
j = json.loads(injson)
|
||||
r = json.dumps(j)
|
||||
|
||||
report = kismetexternal.datasource_pb2.SubJson()
|
||||
|
||||
dt = datetime.now()
|
||||
report.time_sec = int(time.mktime(dt.timetuple()))
|
||||
report.time_usec = int(dt.microsecond)
|
||||
|
||||
report.type = "RTLadsb"
|
||||
report.json = r
|
||||
|
||||
# print("python sending json report", r);
|
||||
|
||||
self.kismet.send_datasource_data_report(full_json=report)
|
||||
except ValueError as e:
|
||||
print(e)
|
||||
self.kismet.send_datasource_error_report(message = "Could not parse JSON output of rtladsb")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(e)
|
||||
self.kismet.send_datasource_error_report(message = "Could not process output of rtladsb")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,25 +0,0 @@
|
|||
include ../Makefile.inc
|
||||
|
||||
MONITOR_BIN = kismet_cap_sdr_rtladsb
|
||||
MQTTMONITOR_BIN = kismet_cap_sdr_rtladsb_mqtt
|
||||
|
||||
all:
|
||||
( cd KismetCaptureRtladsb/kismetexternal; \
|
||||
$(PROTOCBIN) -I ../../../protobuf_definitions --python_out=. ../../../protobuf_definitions/*.proto; \
|
||||
sed -i -E 's/^import.*_pb2/from . \0/' *_pb2.py ; \
|
||||
)
|
||||
$(PYTHON2) ./setup.py bdist
|
||||
|
||||
install:
|
||||
$(PYTHON2) ./setup.py install
|
||||
# These are now part of the setup.py install
|
||||
# $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) aircraft_db.csv $(ETC)/kismet_aircraft_db.csv
|
||||
# $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) $(MONITOR_BIN) $(BIN)/$(MONITOR_BIN)
|
||||
# $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) $(MQTTMONITOR_BIN) $(BIN)/$(MQTTMONITOR_BIN)
|
||||
|
||||
protobuf:
|
||||
$(PROTOCBIN) -I ../protobuf_definitions --python_out=./KismetCaptureRtladsb ../protobuf_definitions/*.proto
|
||||
|
||||
clean:
|
||||
@-$(PYTHON2) ./setup.py clean
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
Kismet RTLADSB Support
|
||||
|
||||
- UNDER DEVELOPMENT -
|
||||
|
||||
The rtl-sdr support in Kismet is under heavy development, not all
|
||||
features are complete at this time. Most of this code is adapted
|
||||
from Dragorn's rtl_433 support.
|
||||
|
||||
- RTL-SDR -
|
||||
|
||||
The Kismet rtladsb SDR capture requires a RTL-SDR USB device; you
|
||||
can learn more about these on the main RTL-SDR website:
|
||||
https://www.rtl-sdr.com
|
||||
|
||||
The RTL-SDR is typically an extremely low-cost USB device which
|
||||
can perform limited raw radio capture. While often *extremely*
|
||||
limited, the RTL-SDR is still capable of a surprising amount of
|
||||
useful capture.
|
||||
|
||||
To use the RTL SDR capture device, you will need a rtlsdr;
|
||||
your Wi-Fi card cannot receive the signal.
|
||||
|
||||
- RTLADSB -
|
||||
|
||||
Kismet requires the rtl_adsb tool be installed. The rtl_adsb
|
||||
tool can typically be installed as package by your distribution
|
||||
or compiled as part of the pybombs system.
|
||||
|
||||
rtl_adsb is able capture and decode the ADSB signal transmitted
|
||||
from a varity of aircraft. For more information about this
|
||||
signal and how to decode it, you can visit
|
||||
|
||||
https://mode-s.org/decode/adsb/introduction.html
|
||||
|
||||
- CONFIGURING RTLADSB -
|
||||
|
||||
The only configuration necessary to configure rtladsb is to make
|
||||
sure that your user has access to the rtlsdr USB device.
|
||||
This is usually accomplished by installing the udev rules which
|
||||
accompany librtlsdr.
|
||||
|
||||
Typically the group `plugdev` is given access; make sure the
|
||||
user you plan to run Kismet as is in that group.
|
||||
|
||||
For more information, check the documentation that came with
|
||||
librtlsdr or the rtlsdr website:
|
||||
https://rtl-sdr.com
|
||||
|
||||
- CONFIGURING KISMET -
|
||||
|
||||
The Kismet capture driver is implemented as a Python datasource;
|
||||
you will need the Kismet-related Python modules from the
|
||||
python_modules/ directory of Kismet (which will be installed
|
||||
automatically in most cases).
|
||||
|
||||
The rtladsb support also requires the NumPy Python module; you can
|
||||
typically get this as a package from your distribution (often
|
||||
python-numpy) or via pip.
|
||||
|
||||
rtlsdr hardware will be automatically detected and shown in the
|
||||
Datasources window, or it can be configured as 'rtladsb-X',
|
||||
where 'X' is the radio you wish to use. If you have only one
|
||||
radio, this will always be zero; for instance:
|
||||
|
||||
source=rtladsb-0:name=some_sdr
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
"""
|
||||
rtladsb Kismet data source
|
||||
|
||||
Implements a rtladsb datasource for Kismet, using the
|
||||
KismetCapturertladsb Python module
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
||||
try:
|
||||
import KismetCaptureRtladsb
|
||||
except ImportError as e:
|
||||
print("Could not import the KismetCaptureRtladsb Python code; you are likely missing")
|
||||
print("a Python dependency or the KismetCaptureRtladsb python module is not installed:")
|
||||
print(e)
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.tracebacklimit = 0
|
||||
|
||||
rtl = KismetCaptureRtladsb.KismetRtladsb()
|
||||
|
||||
# Go into sleep mode
|
||||
while rtl.is_running():
|
||||
time.sleep(1)
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
"""
|
||||
rtladsb Kismet data source
|
||||
|
||||
Implements a rtladsb datasource for Kismet, using the
|
||||
KismetCaptureRtladsb Python module
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
||||
try:
|
||||
import KismetCaptureRtladsb
|
||||
except ImportError as e:
|
||||
print("Could not import the KismetCaptureRtladsb Python code; you are likely missing")
|
||||
print("a Python dependency or the KismetCaptureRtladsb python module is not installed:")
|
||||
print(e)
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.tracebacklimit = 0
|
||||
|
||||
rtl = KismetCaptureRtladsb.KismetRtladsb(mqtt=True)
|
||||
|
||||
# Go into sleep mode
|
||||
while rtl.is_running():
|
||||
time.sleep(1)
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(name='KismetCaptureRtladsb',
|
||||
version='2018.5.1',
|
||||
description='Kismet rtladsb datasource',
|
||||
author='Russ Handorf / @dntlookbehindu',
|
||||
author_email='russell@handorf.com',
|
||||
url='https://www.handorf.com/',
|
||||
install_requires=['numpy', 'protobuf'],
|
||||
packages=find_packages(),
|
||||
scripts=['kismet_cap_sdr_rtladsb', 'kismet_cap_sdr_rtladsb_mqtt'],
|
||||
# data_files=[('share/kismet_rtladsb', ['data/aircraft_db.csv'])]
|
||||
package_data={'KismetCaptureRtladsb': ['data/aircraft_db.csv']},
|
||||
)
|
||||
|
||||
|
|
@ -1,451 +0,0 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
"""
|
||||
rtlamr Kismet data source
|
||||
|
||||
Supports both local usb rtlsdr devices via the rtlamr binary, remote capture
|
||||
from a usb rtlsdr, and remote capture from a mqtt stream, if paho mqtt is
|
||||
installed.
|
||||
|
||||
Sources are generated as rtlamr-XYZ when multiple rtl radios are detected.
|
||||
|
||||
Accepts standard options:
|
||||
channel=freqMHz (in mhz)
|
||||
channel=freqKHz (in khz)
|
||||
channel=freq (in raw hz to rtlamr)
|
||||
|
||||
channels="a,b,c" Pass hopping list to rtlamr_bin
|
||||
|
||||
Additionally accepts:
|
||||
ppm_error Passed as -p to rtlamr
|
||||
gain Passed as -g to rtlamr
|
||||
|
||||
mqtt MQTT server
|
||||
mqtt_port MQTT port (default 1883)
|
||||
mqtt_channel MQTT channel (default rtlamr)
|
||||
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import ctypes
|
||||
from datetime import datetime
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import uuid
|
||||
|
||||
from . import kismetexternal
|
||||
|
||||
try:
|
||||
import paho.mqtt.client as mqtt
|
||||
has_mqtt = True
|
||||
except ImportError:
|
||||
has_mqtt = False
|
||||
|
||||
class KismetRtlamr(object):
|
||||
def __init__(self, mqtt = False):
|
||||
self.mqtt_mode = mqtt
|
||||
|
||||
self.opts = {}
|
||||
|
||||
self.opts['rtlbin'] = 'rtlamr'
|
||||
self.opts['channel'] = "912.600155MHz"
|
||||
self.opts['gain'] = None
|
||||
self.opts['device'] = None
|
||||
|
||||
# Thread that runs the RTL popen
|
||||
self.rtl_thread = None
|
||||
# The popen'd RTL binary
|
||||
self.rtl_exec = None
|
||||
|
||||
# Are we killing rtl because we're reconfiguring?
|
||||
self.rtl_reconfigure = False
|
||||
|
||||
# We're usually not remote
|
||||
self.proberet = None
|
||||
|
||||
# Do we have librtl?
|
||||
self.have_librtl = False
|
||||
|
||||
if not self.mqtt_mode:
|
||||
self.driverid = "rtlamr"
|
||||
# Use ctypes to load librtlsdr and probe for supported USB devices
|
||||
try:
|
||||
self.rtllib = ctypes.CDLL("librtlsdr.so.0")
|
||||
|
||||
self.rtl_get_device_count = self.rtllib.rtlsdr_get_device_count
|
||||
self.rtl_get_device_name = self.rtllib.rtlsdr_get_device_name
|
||||
self.rtl_get_device_name.argtypes = [ctypes.c_int]
|
||||
self.rtl_get_device_name.restype = ctypes.c_char_p
|
||||
self.rtl_get_usb_strings = self.rtllib.rtlsdr_get_device_usb_strings
|
||||
self.rtl_get_usb_strings.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p]
|
||||
self.have_librtl = True
|
||||
except OSError:
|
||||
self.have_librtl = False
|
||||
else:
|
||||
self.driverid = "rtlamrmqtt"
|
||||
|
||||
parser = argparse.ArgumentParser(description='RTLamr to Kismet bridge - Creates a rtlamr data source on a Kismet server and passes JSON-based records from the rtlamr binary',
|
||||
epilog='Requires the rtlamr tool (install your distributions package or compile from https://github.com/bemasher/rtlamr)')
|
||||
|
||||
parser.add_argument('--in-fd', action="store", type=int, dest="infd")
|
||||
parser.add_argument('--out-fd', action="store", type=int, dest="outfd")
|
||||
parser.add_argument('--connect', action="store", dest="connect")
|
||||
parser.add_argument("--source", action="store", dest="source")
|
||||
|
||||
self.config = parser.parse_args()
|
||||
|
||||
if not self.config.connect == None and self.config.source == None:
|
||||
print("You must specify a source with --source when connecting to a remote Kismet server")
|
||||
sys.exit(0)
|
||||
|
||||
if not self.config.source == None:
|
||||
(source, options) = kismetexternal.Datasource.parse_definition(self.config.source)
|
||||
|
||||
if source == None:
|
||||
print("Could not parse the --source option; this should be a standard Kismet source definition.")
|
||||
sys.exit(0)
|
||||
|
||||
self.proberet = self.datasource_probesource(source, options)
|
||||
|
||||
if self.proberet == None:
|
||||
print("Could not configure local source {}, check your source options and config.")
|
||||
sys.exit(0)
|
||||
|
||||
if not "success" in self.proberet:
|
||||
print("Could not configure local source {}, check your source options and config.")
|
||||
if "message" in self.proberet:
|
||||
print(self.proberet["message"])
|
||||
sys.exit(0)
|
||||
|
||||
if not self.proberet["success"]:
|
||||
print("Could not configure local source {}, check your source options and config.")
|
||||
if "message" in self.proberet:
|
||||
print(self.proberet["message"])
|
||||
sys.exit(0)
|
||||
|
||||
print("Connecting to remote server {}".format(self.config.connect))
|
||||
|
||||
self.kismet = kismetexternal.Datasource(self.config.infd, self.config.outfd, remote = self.config.connect)
|
||||
|
||||
self.kismet.set_configsource_cb(self.datasource_configure)
|
||||
self.kismet.set_listinterfaces_cb(self.datasource_listinterfaces)
|
||||
self.kismet.set_opensource_cb(self.datasource_opensource)
|
||||
self.kismet.set_probesource_cb(self.datasource_probesource)
|
||||
|
||||
# If we're connecting remote, kick a newsource
|
||||
if self.proberet:
|
||||
print("Registering remote source {} {}".format(self.driverid, self.config.source))
|
||||
self.kismet.send_datasource_newsource(self.config.source, self.driverid, self.proberet['uuid'])
|
||||
|
||||
self.kismet.start()
|
||||
|
||||
def is_running(self):
|
||||
return self.kismet.is_running()
|
||||
|
||||
def get_rtl_usb_info(self, index):
|
||||
# Allocate memory buffers
|
||||
usb_manuf = (ctypes.c_char * 256)()
|
||||
usb_product = (ctypes.c_char * 256)()
|
||||
usb_serial = (ctypes.c_char * 256)()
|
||||
|
||||
# Call the library
|
||||
self.rtl_get_usb_strings(index, usb_manuf, usb_product, usb_serial)
|
||||
|
||||
# If there's a smarter way to do this, patches welcome
|
||||
m = bytearray(usb_manuf)
|
||||
p = bytearray(usb_product)
|
||||
s = bytearray(usb_serial)
|
||||
|
||||
# Return tuple
|
||||
return (m.decode('ascii'), p.decode('ascii'), s.decode('ascii'))
|
||||
|
||||
def check_rtl_bin(self):
|
||||
try:
|
||||
FNULL = open(os.devnull, 'w')
|
||||
r = subprocess.check_call([self.opts['rtlbin'], "--help"], stdout=FNULL, stderr=FNULL)
|
||||
except subprocess.CalledProcessError:
|
||||
return True
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def __rtl_thread(self):
|
||||
""" Internal thread for running the rtl binary """
|
||||
cmd = [ self.opts['rtlbin'], '-format', 'json' ]
|
||||
|
||||
if self.opts['device'] is not None:
|
||||
cmd.append('-server=127.0.0.1:1234')
|
||||
|
||||
if self.opts['gain'] is not None:
|
||||
cmd.append('-tunergain=')
|
||||
cmd.append("{}".format(self.opts['gain']))
|
||||
|
||||
|
||||
seen_any_valid = False
|
||||
failed_once = False
|
||||
|
||||
try:
|
||||
FNULL = open(os.devnull, 'w')
|
||||
self.rtl_exec = subprocess.Popen(cmd, stderr=FNULL, stdout=subprocess.PIPE)
|
||||
|
||||
while True:
|
||||
l = self.rtl_exec.stdout.readline()
|
||||
|
||||
if not self.handle_json(l):
|
||||
raise RuntimeError('could not process response from rtlamr')
|
||||
|
||||
seen_any_valid = True
|
||||
|
||||
|
||||
except Exception as e:
|
||||
# Catch all errors, but don't die if we're reconfiguring rtl; then we need
|
||||
# to relaunch the binary
|
||||
if not self.rtl_reconfigure:
|
||||
self.kismet.send_datasource_error_report(message = "Unable to process output from rtlamr: {}".format(e))
|
||||
finally:
|
||||
if not seen_any_valid and not self.rtl_reconfigure:
|
||||
self.kismet.send_datasource_error_report(message = "An error occurred in rtlamr and no valid devices were seen; is your USB device plugged in? Try running rtlamr in a terminal and confirm that it can connect to your device.")
|
||||
self.kismet.spindown()
|
||||
|
||||
self.rtl_exec.kill()
|
||||
|
||||
|
||||
def run_rtlamr(self):
|
||||
if self.rtl_thread != None:
|
||||
# Turn on reconfigure mode
|
||||
if self.rtl_exec != None:
|
||||
self.rtl_reconfigure = True
|
||||
self.rtl_exec.kill(9)
|
||||
|
||||
# Let the thread spin down and turn off reconfigure mode
|
||||
self.rtl_thread.join()
|
||||
self.rtl_reconfigure = False
|
||||
|
||||
self.rtl_thread = threading.Thread(target=self.__rtl_thread)
|
||||
self.rtl_thread.daemon = True
|
||||
self.rtl_thread.start()
|
||||
|
||||
def __mqtt_thread(self):
|
||||
self.mq.loop_forever()
|
||||
|
||||
def run_mqtt(self, options):
|
||||
def on_msg(client, user, msg):
|
||||
if not self.handle_json(msg.payload):
|
||||
raise RuntimeError('could not post data')
|
||||
|
||||
opts = options
|
||||
opts.setdefault("mqtt", 'localhost')
|
||||
opts.setdefault("mqtt_port", '1883')
|
||||
opts.setdefault("mqtt_channel", 'rtlamr')
|
||||
|
||||
self.mq = mqtt.Client()
|
||||
self.mq.on_message = on_msg
|
||||
self.mq.connect(opts['mqtt'], int(opts['mqtt_port']))
|
||||
self.mq.subscribe(opts['mqtt_channel'])
|
||||
|
||||
self.mq_thread = threading.Thread(target=self.__mqtt_thread)
|
||||
self.mq_thread.daemon = True
|
||||
self.mq_thread.start()
|
||||
|
||||
|
||||
# Implement the listinterfaces callback for the datasource api;
|
||||
def datasource_listinterfaces(self, seqno):
|
||||
interfaces = []
|
||||
|
||||
if not self.check_rtl_bin():
|
||||
self.kismet.send_datasource_interfaces_report(seqno, interfaces)
|
||||
return
|
||||
|
||||
if self.rtllib != None:
|
||||
for i in range(0, self.rtl_get_device_count()):
|
||||
intf = kismetexternal.datasource_pb2.SubInterface()
|
||||
intf.interface = "rtlamr-{}".format(i)
|
||||
intf.flags = ""
|
||||
intf.hardware = self.rtl_get_device_name(i)
|
||||
interfaces.append(intf)
|
||||
|
||||
self.kismet.send_datasource_interfaces_report(seqno, interfaces)
|
||||
|
||||
def __get_mqtt_uuid(self, options):
|
||||
opts = options
|
||||
opts.setdefault('mqtt', 'localhost')
|
||||
opts.setdefault('mqtt_port', '1883')
|
||||
opts.setdefault('mqtt_channel', 'kismet')
|
||||
|
||||
mqhash = kismetexternal.Datasource.adler32("{}{}{}".format(opts['mqtt'], opts['mqtt_port'], opts['mqtt_channel']))
|
||||
mqhex = "0000{:02X}".format(mqhash)
|
||||
|
||||
return kismetexternal.Datasource.make_uuid("kismet_cap_sdr_rtlamr", mqhex)
|
||||
|
||||
def __get_rtlsdr_uuid(self, intnum):
|
||||
# Get the USB info
|
||||
(manuf, product, serial) = self.get_rtl_usb_info(intnum)
|
||||
|
||||
# Hash the slot, manuf, product, and serial, to get a unique ID for the UUID
|
||||
devicehash = kismetexternal.Datasource.adler32("{}{}{}{}".format(intnum, manuf, product, serial))
|
||||
devicehex = "0000{:02X}".format(devicehash)
|
||||
|
||||
return kismetexternal.Datasource.make_uuid("kismet_cap_sdr_rtlamr", devicehex)
|
||||
|
||||
# Implement the probesource callback for the datasource api
|
||||
def datasource_probesource(self, source, options):
|
||||
ret = {}
|
||||
|
||||
# Does the source look like 'rtlamr-XYZ'?
|
||||
if not source[:7] == "rtlamr-":
|
||||
return None
|
||||
|
||||
if source[7:] == "mqtt":
|
||||
if not 'mqtt' in options:
|
||||
return None
|
||||
if not has_mqtt:
|
||||
return None
|
||||
|
||||
ret['hardware'] = "MQTT"
|
||||
if ('uuid' in options):
|
||||
ret['uuid'] = options['uuid']
|
||||
else:
|
||||
ret['uuid'] = self.__get_mqtt_uuid(options)
|
||||
else:
|
||||
# Do we have librtl?
|
||||
if not self.have_librtl:
|
||||
return None
|
||||
|
||||
if self.mqtt_mode:
|
||||
return None
|
||||
|
||||
if not self.check_rtl_bin():
|
||||
return None
|
||||
|
||||
try:
|
||||
intnum = int(source[7:])
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
if intnum >= self.rtl_get_device_count():
|
||||
return None
|
||||
|
||||
ret['hardware'] = self.rtl_get_device_name(intnum)
|
||||
if ('uuid' in options):
|
||||
ret['uuid'] = options['uuid']
|
||||
else:
|
||||
ret['uuid'] = self.__get_rtlsdr_uuid(intnum)
|
||||
|
||||
ret['channel'] = self.opts['channel']
|
||||
ret['channels'] = [self.opts['channel']]
|
||||
ret['success'] = True
|
||||
return ret
|
||||
|
||||
def datasource_opensource(self, source, options):
|
||||
ret = {}
|
||||
|
||||
# Does the source look like 'rtlamr-XYZ'?
|
||||
if not source[:7] == "rtlamr-":
|
||||
ret["success"] = False
|
||||
ret["message"] = "Could not parse which rtlsdr device to use"
|
||||
return ret
|
||||
|
||||
intnum = -1
|
||||
|
||||
if source[7:] == "mqtt":
|
||||
if not 'mqtt' in options:
|
||||
ret["success"] = False
|
||||
ret["message"] = "MQTT requested, but no mqtt=xyz option in source definition"
|
||||
return ret
|
||||
if not has_mqtt:
|
||||
ret["success"] = False
|
||||
ret["message"] = "MQTT requested, but the python paho mqtt package is not installed"
|
||||
return ret
|
||||
|
||||
ret['hardware'] = "MQTT"
|
||||
if ('uuid' in options):
|
||||
ret['uuid'] = options['uuid']
|
||||
else:
|
||||
ret['uuid'] = self.__get_mqtt_uuid(options)
|
||||
|
||||
self.mqtt_mode = True
|
||||
else:
|
||||
if not self.have_librtl:
|
||||
ret["success"] = False
|
||||
ret["message"] = "could not find librtlsdr, unable to configure rtlsdr interfaces"
|
||||
return ret
|
||||
|
||||
try:
|
||||
intnum = int(source[7:])
|
||||
except ValueError:
|
||||
ret["success"] = False
|
||||
ret["message"] = "Could not parse rtl device"
|
||||
return ret
|
||||
|
||||
if intnum >= self.rtl_get_device_count():
|
||||
ret["success"] = False
|
||||
ret["message"] = "Could not find rtl-sdr device {}".format(intnum)
|
||||
return ret
|
||||
|
||||
if 'channel' in options:
|
||||
self.opts['channel'] = options['channel']
|
||||
|
||||
ret['hardware'] = self.rtl_get_device_name(intnum)
|
||||
if ('uuid' in options):
|
||||
ret['uuid'] = options['uuid']
|
||||
else:
|
||||
ret['uuid'] = self.__get_rtlsdr_uuid(intnum)
|
||||
|
||||
self.opts['device'] = intnum
|
||||
|
||||
self.mqtt_mode = False
|
||||
|
||||
if not self.mqtt_mode:
|
||||
if not self.check_rtl_bin():
|
||||
ret['success'] = False
|
||||
ret['message'] = "Could not find rtlamr binary; make sure you've installed rtlamr, check the Kismet README for more information."
|
||||
return
|
||||
|
||||
ret['success'] = True
|
||||
|
||||
if self.mqtt_mode:
|
||||
self.run_mqtt(options)
|
||||
else:
|
||||
self.run_rtlamr()
|
||||
|
||||
return ret
|
||||
|
||||
def datasource_configure(self, seqno, config):
|
||||
#print(config)
|
||||
|
||||
return {"success": True}
|
||||
|
||||
def handle_json(self, injson):
|
||||
try:
|
||||
j = json.loads(injson)
|
||||
r = json.dumps(j)
|
||||
|
||||
report = kismetexternal.datasource_pb2.SubJson()
|
||||
|
||||
dt = datetime.now()
|
||||
report.time_sec = int(time.mktime(dt.timetuple()))
|
||||
report.time_usec = int(dt.microsecond)
|
||||
|
||||
report.type = "RTLamr"
|
||||
report.json = r
|
||||
|
||||
# print("python sending json report", r);
|
||||
|
||||
self.kismet.send_datasource_data_report(full_json=report)
|
||||
except ValueError as e:
|
||||
print(e)
|
||||
self.kismet.send_datasource_error_report(message = "Could not parse JSON output of rtlamr")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(e)
|
||||
self.kismet.send_datasource_error_report(message = "Could not process output of rtlamr")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,24 +0,0 @@
|
|||
include ../Makefile.inc
|
||||
|
||||
MONITOR_BIN = kismet_cap_sdr_rtlamr
|
||||
MQTTMONITOR_BIN = kismet_cap_sdr_rtlamr_mqtt
|
||||
|
||||
all:
|
||||
( cd KismetCaptureRtlamr/kismetexternal; \
|
||||
$(PROTOCBIN) -I ../../../protobuf_definitions --python_out=. ../../../protobuf_definitions/*.proto; \
|
||||
sed -i -E 's/^import.*_pb2/from . \0/' *_pb2.py ; \
|
||||
)
|
||||
$(PYTHON2) ./setup.py bdist
|
||||
|
||||
install:
|
||||
$(PYTHON2) ./setup.py install
|
||||
# These are now part of the setup.py install
|
||||
# $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) $(MONITOR_BIN) $(BIN)/$(MONITOR_BIN)
|
||||
# $(INSTALL) -o $(INSTUSR) -g $(INSTGRP) $(MQTTMONITOR_BIN) $(BIN)/$(MQTTMONITOR_BIN)
|
||||
|
||||
protobuf:
|
||||
$(PROTOCBIN) -I ../protobuf_definitions --python_out=./KismetCaptureRtlamr ../protobuf_definitions/*.proto
|
||||
|
||||
clean:
|
||||
@-$(PYTHON2) ./setup.py clean
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
Kismet RTLAMR Support
|
||||
|
||||
- UNDER DEVELOPMENT -
|
||||
|
||||
The rtl-sdr support in Kismet is under heavy development, not all
|
||||
features are complete at this time. Most of this code is adapted
|
||||
from Dragorn's rtl_433 support.
|
||||
|
||||
- RTL-SDR -
|
||||
|
||||
The Kismet rtlamr SDR capture requires a RTL-SDR USB device; you
|
||||
can learn more about these on the main RTL-SDR website:
|
||||
https://www.rtl-sdr.com
|
||||
|
||||
The RTL-SDR is typically an extremely low-cost USB device which
|
||||
can perform limited raw radio capture. While often *extremely*
|
||||
limited, the RTL-SDR is still capable of a surprising amount of
|
||||
useful capture.
|
||||
|
||||
To use the RTL SDR capture device, you will need a rtlsdr;
|
||||
your Wi-Fi card cannot receive the signal.
|
||||
|
||||
- RTLAMR -
|
||||
|
||||
Kismet requires the rtlamr tool be installed. The rtlamr
|
||||
tool has to be installed from source. You can download the
|
||||
source at:
|
||||
https://github.com/bemasher/rtlamr
|
||||
|
||||
To compile this program, follow their instructions. Be warned,
|
||||
it requires Go. It also requires rtl_tcp as a shim between
|
||||
rtlamr and the rtl dongle.
|
||||
|
||||
- CONFIGURING RTLAMR -
|
||||
|
||||
The only configuration necessary to configure rtlamr is to make
|
||||
sure that your user has access to the rtlsdr USB device.
|
||||
This is usually accomplished by installing the udev rules which
|
||||
accompany librtlsdr.
|
||||
|
||||
Typically the group `plugdev` is given access; make sure the
|
||||
user you plan to run Kismet as is in that group.
|
||||
|
||||
For more information, check the documentation that came with
|
||||
librtlsdr or the rtlsdr website:
|
||||
https://rtl-sdr.com
|
||||
|
||||
- CONFIGURING KISMET -
|
||||
|
||||
The Kismet capture driver is implemented as a Python datasource;
|
||||
you will need the Kismet-related Python modules from the
|
||||
python_modules/ directory of Kismet (which will be installed
|
||||
automatically in most cases).
|
||||
|
||||
rtlsdr hardware will be automatically detected and shown in the
|
||||
Datasources window, or it can be configured as 'rtlamr-X',
|
||||
where 'X' is the radio you wish to use. If you have only one
|
||||
radio, this will always be zero; for instance:
|
||||
|
||||
source=rtlamr-0:name=some_sdr
|
||||
|
||||
- GOTCHAS -
|
||||
|
||||
If, for whatever reason, the rtl dongle goes through a reset
|
||||
with udev Kismet might get a little cranky. I've only been able
|
||||
to fix this by manually killing the python process and letting
|
||||
Kismet restart everything automagically. The fix is to write a
|
||||
new app that does everything natively within it. Soon.
|
|
@ -1,30 +0,0 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
"""
|
||||
rtlamr Kismet data source
|
||||
|
||||
Implements a rtlamr datasource for Kismet, using the
|
||||
KismetCapturertlamr Python module
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
||||
try:
|
||||
import KismetCaptureRtlamr
|
||||
except ImportError as e:
|
||||
print("Could not import the KismetCaptureRtlamr Python code; you are likely missing")
|
||||
print("a Python dependency or the KismetCaptureRtlamr python module is not installed:")
|
||||
print(e)
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.tracebacklimit = 0
|
||||
|
||||
rtl = KismetCaptureRtlamr.KismetRtlamr()
|
||||
|
||||
# Go into sleep mode
|
||||
while rtl.is_running():
|
||||
time.sleep(1)
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
"""
|
||||
rtlamr Kismet data source
|
||||
|
||||
Implements a rtlamr datasource for Kismet, using the
|
||||
KismetCaptureRtlamr Python module
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
||||
try:
|
||||
import KismetCaptureRtlamr
|
||||
except ImportError as e:
|
||||
print("Could not import the KismetCaptureRtlamr Python code; you are likely missing")
|
||||
print("a Python dependency or the KismetCaptureRtlamr python module is not installed:")
|
||||
print(e)
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.tracebacklimit = 0
|
||||
|
||||
rtl = KismetCaptureRtlamr.KismetRtlamr(mqtt=True)
|
||||
|
||||
# Go into sleep mode
|
||||
while rtl.is_running():
|
||||
time.sleep(1)
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
#!/usr/bin/env python2
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(name='KismetCaptureRtlamr',
|
||||
version='2018.0.0',
|
||||
description='Kismet rtlamr datasource',
|
||||
author='Russ Handorf / @dntlookbehindu',
|
||||
author_email='russell@handorf.com',
|
||||
url='https://www.handorf.com/',
|
||||
install_requires=['protobuf'],
|
||||
packages=find_packages(),
|
||||
scripts=['kismet_cap_sdr_rtlamr', 'kismet_cap_sdr_rtlamr_mqtt'],
|
||||
)
|
||||
|
||||
|
|
@ -1,360 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "chainbuf.h"
|
||||
#include "util.h"
|
||||
|
||||
Chainbuf::Chainbuf(size_t in_chunk, size_t pre_allocate) {
|
||||
chunk_sz = in_chunk;
|
||||
|
||||
// Allocate slots in the vector, but not bytes
|
||||
buff_vec = std::vector<uint8_t *>();
|
||||
buff_vec.reserve(pre_allocate);
|
||||
|
||||
buff_vec.push_back(new uint8_t[chunk_sz]);
|
||||
|
||||
used_sz = 0;
|
||||
total_sz = 0;
|
||||
|
||||
write_block = 0;
|
||||
write_buf = buff_vec[0];
|
||||
read_block = 0;
|
||||
read_buf = buff_vec[0];
|
||||
write_offt = 0;
|
||||
read_offt = 0;
|
||||
|
||||
free_read = false;
|
||||
free_commit = false;
|
||||
|
||||
alloc_delta = 0;
|
||||
}
|
||||
|
||||
Chainbuf::~Chainbuf() {
|
||||
local_locker lock(&write_mutex);
|
||||
|
||||
// fprintf(stderr, "debug - freeing chainbuf, total size %zu chunks %zu, largest allocation delta %zu\n", total_sz, (total_sz / chunk_sz) + 1, alloc_delta);
|
||||
|
||||
clear();
|
||||
}
|
||||
|
||||
void Chainbuf::clear() {
|
||||
local_locker lock(&write_mutex);
|
||||
|
||||
for (auto x : buff_vec)
|
||||
delete[](x);
|
||||
|
||||
buff_vec.clear();
|
||||
}
|
||||
|
||||
size_t Chainbuf::used() {
|
||||
local_locker lock(&write_mutex);
|
||||
|
||||
return used_sz;
|
||||
}
|
||||
|
||||
size_t Chainbuf::total() {
|
||||
local_locker lock(&write_mutex);
|
||||
|
||||
return total_sz;
|
||||
}
|
||||
|
||||
ssize_t Chainbuf::write(uint8_t *in_data, size_t in_sz) {
|
||||
local_locker lock(&write_mutex);
|
||||
|
||||
size_t total_written = 0;
|
||||
|
||||
while (total_written < in_sz) {
|
||||
// Available in this chunk
|
||||
size_t free_chunk_sz = chunk_sz - write_offt;
|
||||
|
||||
// Whole buffer or whole chunk
|
||||
size_t w_sz = std::min(in_sz - total_written, free_chunk_sz);
|
||||
|
||||
if (in_data != NULL) {
|
||||
if (w_sz == 1)
|
||||
write_buf[write_offt] = in_data[total_written];
|
||||
else {
|
||||
memcpy(write_buf + write_offt, in_data + total_written, w_sz);
|
||||
}
|
||||
}
|
||||
|
||||
write_offt += w_sz;
|
||||
|
||||
total_written += w_sz;
|
||||
|
||||
used_sz += w_sz;
|
||||
total_sz += w_sz;
|
||||
|
||||
// If we got here and we have more data, then we must need another chunk
|
||||
if (total_written < in_sz) {
|
||||
uint8_t *newchunk = new uint8_t[chunk_sz];
|
||||
buff_vec.push_back(newchunk);
|
||||
write_block++;
|
||||
write_buf = buff_vec[write_block];
|
||||
|
||||
// fprintf(stderr, "debug - allocated new chunk %u\n", write_block);
|
||||
|
||||
if (read_buf == NULL) {
|
||||
read_buf = buff_vec[read_block];
|
||||
}
|
||||
|
||||
// Track the max simultaneously allocated
|
||||
if (write_block - read_block > alloc_delta)
|
||||
alloc_delta = write_block - read_block;
|
||||
|
||||
write_offt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return total_written;
|
||||
}
|
||||
|
||||
ssize_t Chainbuf::peek(uint8_t **ret_data, size_t in_sz) {
|
||||
local_eol_locker peeklock(&write_mutex);
|
||||
|
||||
if (peek_reserved) {
|
||||
throw std::runtime_error("chainbuf peek already locked");
|
||||
}
|
||||
|
||||
if (used() == 0) {
|
||||
free_read = false;
|
||||
peek_reserved = true;
|
||||
|
||||
*ret_data = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t goal_sz = std::min(used(), in_sz);
|
||||
|
||||
// If we're contiguous
|
||||
if (read_offt + goal_sz < chunk_sz) {
|
||||
free_read = false;
|
||||
peek_reserved = true;
|
||||
|
||||
*ret_data = read_buf + read_offt;
|
||||
return goal_sz;
|
||||
}
|
||||
|
||||
// Otherwise we have to copy it out; copy through every block until we
|
||||
// hit the max length
|
||||
free_read = true;
|
||||
peek_reserved = true;
|
||||
*ret_data = new uint8_t[goal_sz];
|
||||
|
||||
size_t left = goal_sz;
|
||||
size_t offt = read_offt;
|
||||
size_t block_offt = 0;
|
||||
size_t copy_offt = 0;
|
||||
|
||||
while (left) {
|
||||
if (read_block + block_offt >= buff_vec.size())
|
||||
throw std::runtime_error("chainbuf ran out of room in buffer vector during peek");
|
||||
|
||||
size_t copy_sz = chunk_sz - offt;
|
||||
if (left < copy_sz)
|
||||
copy_sz = left;
|
||||
|
||||
// Copy whatever space we have in the buffer remaining
|
||||
memcpy(*ret_data + copy_offt, read_buf + block_offt + offt, copy_sz);
|
||||
// Subtract what we just copied
|
||||
left -= copy_sz;
|
||||
// Start at the beginning of the next buffer
|
||||
offt = 0;
|
||||
// Jump to the next buffer
|
||||
block_offt++;
|
||||
// Jump our buffer ahead by the same amount
|
||||
copy_offt += copy_sz;
|
||||
}
|
||||
|
||||
return goal_sz;
|
||||
}
|
||||
|
||||
ssize_t Chainbuf::zero_copy_peek(uint8_t **ret_data, size_t in_sz) {
|
||||
local_eol_locker peeklock(&write_mutex);
|
||||
|
||||
if (peek_reserved) {
|
||||
throw std::runtime_error("chainbuf peek already locked");
|
||||
}
|
||||
|
||||
if (used() == 0) {
|
||||
free_read = false;
|
||||
peek_reserved = true;
|
||||
|
||||
*ret_data = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (read_buf == NULL) {
|
||||
fprintf(stderr, "read in null at block %u used %zu\n", read_block, used());
|
||||
throw std::runtime_error("chainbuf advanced into null readbuf");
|
||||
}
|
||||
|
||||
// fprintf(stderr, "debug - chainbuf peeking read_block %u\n", read_block);
|
||||
|
||||
// Pick the least size: a zero-copy of our buffer, the requested size,
|
||||
// or the amount actually used
|
||||
size_t goal_sz = std::min(chunk_sz - read_offt, in_sz);
|
||||
goal_sz = std::min(goal_sz, used());
|
||||
|
||||
*ret_data = read_buf + read_offt;
|
||||
|
||||
peek_reserved = true;
|
||||
free_read = false;
|
||||
|
||||
return goal_sz;
|
||||
}
|
||||
|
||||
void Chainbuf::peek_free(unsigned char *in_data) {
|
||||
local_unlocker unpeeklock(&write_mutex);
|
||||
|
||||
if (!peek_reserved) {
|
||||
throw std::runtime_error("chainbuf peek_free on unlocked buffer");
|
||||
}
|
||||
|
||||
if (free_read && in_data != NULL) {
|
||||
delete[] in_data;
|
||||
}
|
||||
|
||||
peek_reserved = false;
|
||||
free_read = false;
|
||||
}
|
||||
|
||||
size_t Chainbuf::consume(size_t in_sz) {
|
||||
// Protect against crossthread
|
||||
local_locker writelock(&write_mutex);
|
||||
|
||||
if (peek_reserved) {
|
||||
throw std::runtime_error("chainbuf consume while peeked data pending");
|
||||
}
|
||||
|
||||
if (write_reserved) {
|
||||
throw std::runtime_error("chainbuf consume while write block is reserved");
|
||||
}
|
||||
|
||||
ssize_t consumed_sz = 0;
|
||||
int block_offt = 0;
|
||||
|
||||
while (consumed_sz < (ssize_t) in_sz) {
|
||||
ssize_t rd_sz = 0;
|
||||
|
||||
// If we've wandered out of our block...
|
||||
if (read_block + block_offt >= buff_vec.size())
|
||||
throw std::runtime_error("chainbuf ran out of room in buffer vector "
|
||||
"during consume");
|
||||
|
||||
// Get either the remaining data, or the remaining chunk
|
||||
rd_sz = std::min(in_sz - consumed_sz, chunk_sz - read_offt);
|
||||
|
||||
// Jump ahead
|
||||
consumed_sz += rd_sz;
|
||||
|
||||
// Jump the read offset
|
||||
read_offt += rd_sz;
|
||||
|
||||
// fprintf(stderr, "debug - chainbuf - consumed, read_offt %zu\n", read_offt);
|
||||
|
||||
// We've jumped to the next block...
|
||||
if (read_offt >= chunk_sz) {
|
||||
// fprintf(stderr, "debug - read consumed %u, deleting\n", read_block);
|
||||
|
||||
// Universal read offt jumps
|
||||
read_offt = 0;
|
||||
|
||||
// Data consuming block offt jumps
|
||||
block_offt++;
|
||||
|
||||
// Remove the old read block and set the slot to null
|
||||
// fprintf(stderr, "debug - chainbuf read_block freeing %u\n", read_block);
|
||||
delete[](buff_vec[read_block]);
|
||||
buff_vec[read_block] = NULL;
|
||||
|
||||
// Move the global read pointer
|
||||
read_block++;
|
||||
|
||||
if (read_block < buff_vec.size())
|
||||
read_buf = buff_vec[read_block];
|
||||
else
|
||||
read_buf = NULL;
|
||||
|
||||
// fprintf(stderr, "debug - chainbuf - moved read_buf to %p\n", read_buf);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// fprintf(stderr, "debug - chainbuf - consumed %zu used %zu\n", consumed_sz, used_sz);
|
||||
used_sz -= consumed_sz;
|
||||
return consumed_sz;
|
||||
}
|
||||
|
||||
ssize_t Chainbuf::reserve(unsigned char **data, size_t in_sz) {
|
||||
local_eol_locker writelock(&write_mutex);
|
||||
|
||||
if (write_reserved) {
|
||||
throw std::runtime_error("chainbuf already locked");
|
||||
}
|
||||
|
||||
// If we can fit inside the chunk we're in now...
|
||||
if (in_sz < chunk_sz - write_offt) {
|
||||
*data = write_buf + write_offt;
|
||||
free_commit = false;
|
||||
return in_sz;
|
||||
}
|
||||
|
||||
// Otherwise we're going to have to malloc a chunk
|
||||
*data = new unsigned char[in_sz];
|
||||
free_commit = true;
|
||||
return in_sz;
|
||||
}
|
||||
|
||||
ssize_t Chainbuf::zero_copy_reserve(unsigned char **data, size_t in_sz) {
|
||||
// We can't do better than our zero copy attempt
|
||||
return reserve(data, in_sz);
|
||||
}
|
||||
|
||||
bool Chainbuf::commit(unsigned char *data, size_t in_sz) {
|
||||
local_unlocker unwritelock(&write_mutex);
|
||||
|
||||
if (!write_reserved) {
|
||||
throw std::runtime_error("chainbuf no pending commit");
|
||||
}
|
||||
|
||||
// Unlock the write state
|
||||
write_reserved = false;
|
||||
|
||||
// If we have allocated an interstitial buffer, we need copy the data over and delete
|
||||
// the temp buffer
|
||||
if (free_commit) {
|
||||
free_commit = false;
|
||||
|
||||
ssize_t written = write(data, in_sz);
|
||||
|
||||
delete[] data;
|
||||
|
||||
if (written < 0)
|
||||
return false;
|
||||
|
||||
return (size_t) written == in_sz;
|
||||
} else {
|
||||
ssize_t written = write(NULL, in_sz);
|
||||
if (written < 0)
|
||||
return false;
|
||||
|
||||
return (size_t) written == in_sz;
|
||||
}
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __CHAINBUF_H__
|
||||
#define __CHAINBUF_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
|
||||
#include "buffer_handler.h"
|
||||
|
||||
/* Fairly basic linked buffer system which allows linear writing and linear reading.
|
||||
* Random access is not supported; use a string buffer for that.
|
||||
*
|
||||
* The linked buffer is best used for buffering serialized output before sending it
|
||||
* to the webserver as a stream - minimal copying is needed.
|
||||
*
|
||||
* Due to some implementation limitations this should probably only be used to stream
|
||||
* to a write sink - such as writing to a http endpoint. Read and peek operations will
|
||||
* only return the remaining portion of the current slot as they operate purely on
|
||||
* the chunk and prevent memory copying.
|
||||
*
|
||||
*/
|
||||
|
||||
class Chainbuf : public CommonBuffer {
|
||||
public:
|
||||
// Size per chunk and number of slots to pre-allocate in the buffer
|
||||
Chainbuf(size_t in_chunk = 1024, size_t pre_allocate = 128);
|
||||
virtual ~Chainbuf();
|
||||
|
||||
// Erase buffer
|
||||
virtual void clear();
|
||||
|
||||
// Return amount used in buffer
|
||||
virtual size_t used();
|
||||
|
||||
// Return about available (effectively "infinite"), use a crappy hack for now and
|
||||
// always return the chunk size
|
||||
virtual ssize_t available() {
|
||||
return chunk_sz;
|
||||
}
|
||||
|
||||
virtual ssize_t size() {
|
||||
return chunk_sz;
|
||||
}
|
||||
|
||||
// Total size ever used by buffer
|
||||
virtual size_t total();
|
||||
|
||||
// Peek from buffer; will only return up to chunk size per peek
|
||||
virtual ssize_t peek(unsigned char **ret_data, size_t in_sz);
|
||||
virtual ssize_t zero_copy_peek(unsigned char **ret_data, size_t in_sz);
|
||||
virtual void peek_free(unsigned char *in_data);
|
||||
|
||||
// Write amount to buffer, arbitrarily allocating new chunks
|
||||
virtual ssize_t write(unsigned char *in_data, size_t in_sz);
|
||||
|
||||
virtual ssize_t reserve(unsigned char **data, size_t in_sz);
|
||||
virtual ssize_t zero_copy_reserve(unsigned char **data, size_t in_sz);
|
||||
virtual bool commit(unsigned char *data, size_t in_sz);
|
||||
|
||||
// Consume from buffer
|
||||
size_t consume(size_t in_sz);
|
||||
|
||||
protected:
|
||||
size_t chunk_sz;
|
||||
bool free_after_read;
|
||||
|
||||
unsigned int write_block;
|
||||
uint8_t *write_buf;
|
||||
size_t write_offt;
|
||||
unsigned int read_block;
|
||||
uint8_t *read_buf;
|
||||
size_t read_offt;
|
||||
|
||||
std::vector<uint8_t *> buff_vec;
|
||||
|
||||
size_t used_sz;
|
||||
size_t total_sz;
|
||||
|
||||
std::atomic<bool> free_read, free_commit;
|
||||
|
||||
size_t alloc_delta;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,302 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include "channeltracker2.h"
|
||||
#include "json_adapter.h"
|
||||
#include "devicetracker.h"
|
||||
#include "devicetracker_component.h"
|
||||
#include "packinfo_signal.h"
|
||||
|
||||
Channeltracker_V2::Channeltracker_V2(GlobalRegistry *in_globalreg) :
|
||||
tracker_component(),
|
||||
Kis_Net_Httpd_CPPStream_Handler() {
|
||||
|
||||
// Number of seconds we consider a device to be active on a frequency
|
||||
// after the last time we see it
|
||||
device_decay = 5;
|
||||
|
||||
register_fields();
|
||||
reserve_fields(NULL);
|
||||
|
||||
auto packetchain = Globalreg::FetchMandatoryGlobalAs<Packetchain>("PACKETCHAIN");
|
||||
|
||||
packetchain->RegisterHandler(&PacketChainHandler, this, CHAINPOS_LOGGING, 0);
|
||||
|
||||
pack_comp_device = packetchain->RegisterPacketComponent("DEVICE");
|
||||
pack_comp_common = packetchain->RegisterPacketComponent("COMMON");
|
||||
pack_comp_l1data = packetchain->RegisterPacketComponent("RADIODATA");
|
||||
|
||||
devicetracker =
|
||||
Globalreg::FetchMandatoryGlobalAs<Devicetracker>("DEVICETRACKER");
|
||||
|
||||
struct timeval trigger_tm;
|
||||
trigger_tm.tv_sec = time(0) + 1;
|
||||
trigger_tm.tv_usec = 0;
|
||||
|
||||
timetracker =
|
||||
Globalreg::FetchMandatoryGlobalAs<Timetracker>("TIMETRACKER");
|
||||
|
||||
timer_id = timetracker->RegisterTimer(0, &trigger_tm, 0, this);
|
||||
|
||||
Bind_Httpd_Server();
|
||||
}
|
||||
|
||||
Channeltracker_V2::~Channeltracker_V2() {
|
||||
local_locker locker(&lock);
|
||||
|
||||
auto timetracker = Globalreg::FetchGlobalAs<Timetracker>("TIMETRACKER");
|
||||
if (timetracker != nullptr)
|
||||
timetracker->RemoveTimer(timer_id);
|
||||
|
||||
auto packetchain = Globalreg::FetchGlobalAs<Packetchain>("PACKETCHAIN");
|
||||
if (packetchain != nullptr)
|
||||
packetchain->RemoveHandler(&PacketChainHandler, CHAINPOS_LOGGING);
|
||||
|
||||
Globalreg::globalreg->RemoveGlobal("CHANNEL_TRACKER");
|
||||
}
|
||||
|
||||
void Channeltracker_V2::register_fields() {
|
||||
tracker_component::register_fields();
|
||||
|
||||
RegisterField("kismet.channeltracker.frequency_map", "Frequency use", &frequency_map);
|
||||
RegisterField("kismet.channeltracker.channel_map", "Channel use", &channel_map);
|
||||
|
||||
channel_entry_id =
|
||||
RegisterField("kismet.channeltracker.channel",
|
||||
TrackerElementFactory<Channeltracker_V2_Channel>(),
|
||||
"channel/frequency entry");
|
||||
}
|
||||
|
||||
bool Channeltracker_V2::Httpd_VerifyPath(const char *path, const char *method) {
|
||||
if (strcmp(method, "GET") != 0)
|
||||
return false;
|
||||
|
||||
if (!Httpd_CanSerialize(path))
|
||||
return false;
|
||||
|
||||
std::string stripped = Httpd_StripSuffix(path);
|
||||
|
||||
if (stripped == "/channels/channels")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Channeltracker_V2::Httpd_CreateStreamResponse(
|
||||
Kis_Net_Httpd *httpd __attribute__((unused)),
|
||||
Kis_Net_Httpd_Connection *connection __attribute__((unused)),
|
||||
const char *path, const char *method,
|
||||
const char *upload_data __attribute__((unused)),
|
||||
size_t *upload_data_size __attribute__((unused)),
|
||||
std::stringstream &stream) {
|
||||
|
||||
if (strcmp(method, "GET") != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string stripped = Httpd_StripSuffix(path);
|
||||
|
||||
if (stripped == "/channels/channels") {
|
||||
local_shared_locker locker(&lock);
|
||||
auto cv2 = Globalreg::FetchMandatoryGlobalAs<Channeltracker_V2>("CHANNEL_TRACKER");
|
||||
Httpd_Serialize(path, stream, cv2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class channeltracker_v2_device_worker : public DevicetrackerFilterWorker {
|
||||
public:
|
||||
channeltracker_v2_device_worker(Channeltracker_V2 *channelv2) {
|
||||
this->channelv2 = channelv2;
|
||||
stime = time(0);
|
||||
}
|
||||
|
||||
virtual ~channeltracker_v2_device_worker() { }
|
||||
|
||||
// Count all the devices. We use a filter worker but 'match' on all
|
||||
// and count them into our local map
|
||||
virtual bool MatchDevice(Devicetracker *devicetracker __attribute__((unused)),
|
||||
std::shared_ptr<kis_tracked_device_base> device) {
|
||||
if (device == NULL)
|
||||
return false;
|
||||
|
||||
if (device->get_frequency() == 0)
|
||||
return false;
|
||||
|
||||
{
|
||||
local_locker lock(&workermutex);
|
||||
|
||||
auto i = device_count.find(device->get_frequency());
|
||||
|
||||
if (i != device_count.end()) {
|
||||
if (device->get_last_time() > (stime - channelv2->device_decay))
|
||||
i->second++;
|
||||
} else {
|
||||
if (device->get_last_time() > (stime - channelv2->device_decay))
|
||||
device_count.insert(std::make_pair(device->get_frequency(), 1));
|
||||
else
|
||||
device_count.insert(std::make_pair(device->get_frequency(), 0));
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Send it back to our channel tracker
|
||||
virtual void Finalize(Devicetracker *devicetracker __attribute__((unused))) {
|
||||
channelv2->update_device_counts(device_count);
|
||||
}
|
||||
|
||||
protected:
|
||||
Channeltracker_V2 *channelv2;
|
||||
|
||||
std::map<double, unsigned int> device_count;
|
||||
|
||||
time_t stime;
|
||||
|
||||
kis_recursive_timed_mutex workermutex;
|
||||
};
|
||||
|
||||
|
||||
int Channeltracker_V2::timetracker_event(int event_id __attribute__((unused))) {
|
||||
local_locker locker(&lock);
|
||||
|
||||
auto worker = std::make_shared<channeltracker_v2_device_worker>(this);
|
||||
devicetracker->MatchOnReadonlyDevices(worker);
|
||||
|
||||
// Reschedule
|
||||
struct timeval trigger_tm;
|
||||
trigger_tm.tv_sec = time(0) + 1;
|
||||
trigger_tm.tv_usec = 0;
|
||||
|
||||
timer_id = timetracker->RegisterTimer(0, &trigger_tm, 0, this);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Channeltracker_V2::update_device_counts(std::map<double, unsigned int> in_counts) {
|
||||
local_locker locker(&lock);
|
||||
time_t ts = time(0);
|
||||
|
||||
for (auto i : in_counts) {
|
||||
auto imi = frequency_map->find(i.first);
|
||||
|
||||
// If we can't find the device, skip it
|
||||
if (imi == frequency_map->end())
|
||||
continue;
|
||||
|
||||
// Update the device RRD for the count
|
||||
std::static_pointer_cast<Channeltracker_V2_Channel>(imi->second)->get_device_rrd()->add_sample(i.second, ts);
|
||||
}
|
||||
}
|
||||
|
||||
int Channeltracker_V2::PacketChainHandler(CHAINCALL_PARMS) {
|
||||
Channeltracker_V2 *cv2 = (Channeltracker_V2 *) auxdata;
|
||||
|
||||
local_locker locker(&(cv2->lock));
|
||||
|
||||
auto l1info = in_pack->fetch<kis_layer1_packinfo>(cv2->pack_comp_l1data);
|
||||
auto common = in_pack->fetch<kis_common_info>(cv2->pack_comp_common);
|
||||
|
||||
// Nothing to do with no l1info
|
||||
if (l1info == nullptr)
|
||||
return 1;
|
||||
|
||||
std::shared_ptr<Channeltracker_V2_Channel> freq_channel;
|
||||
std::shared_ptr<Channeltracker_V2_Channel> chan_channel;
|
||||
|
||||
// Find or make a frequency record if we know our frequency
|
||||
if (l1info->freq_khz != 0) {
|
||||
auto imi = cv2->frequency_map->find(l1info->freq_khz);
|
||||
|
||||
if (imi == cv2->frequency_map->end()) {
|
||||
freq_channel =
|
||||
std::make_shared<Channeltracker_V2_Channel>(cv2->channel_entry_id);
|
||||
freq_channel->set_frequency(l1info->freq_khz);
|
||||
cv2->frequency_map->insert(l1info->freq_khz, freq_channel);
|
||||
} else {
|
||||
freq_channel = std::static_pointer_cast<Channeltracker_V2_Channel>(imi->second);
|
||||
}
|
||||
}
|
||||
|
||||
if (common != nullptr) {
|
||||
if (!(common->channel == "0") && !(common->channel == "")) {
|
||||
auto smi = cv2->channel_map->find(common->channel);
|
||||
|
||||
if (smi == cv2->channel_map->end()) {
|
||||
chan_channel =
|
||||
std::make_shared<Channeltracker_V2_Channel>(cv2->channel_entry_id);
|
||||
|
||||
chan_channel->set_channel(common->channel);
|
||||
cv2->channel_map->insert(common->channel, chan_channel);
|
||||
} else {
|
||||
chan_channel = std::static_pointer_cast<Channeltracker_V2_Channel>(smi->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// didn't find anything
|
||||
if (freq_channel == NULL && chan_channel == NULL)
|
||||
return 1;
|
||||
|
||||
time_t stime = time(0);
|
||||
|
||||
if (freq_channel) {
|
||||
freq_channel->get_signal_data()->append_signal(*l1info, false);
|
||||
freq_channel->get_packets_rrd()->add_sample(1, stime);
|
||||
|
||||
if (common != NULL) {
|
||||
freq_channel->get_data_rrd()->add_sample(common->datasize, stime);
|
||||
|
||||
/*
|
||||
freq_channel->seen_device_map[common->device] = true;
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (chan_channel) {
|
||||
chan_channel->get_signal_data()->append_signal(*l1info, false);
|
||||
chan_channel->get_packets_rrd()->add_sample(1, stime);
|
||||
|
||||
if (common != NULL) {
|
||||
chan_channel->get_data_rrd()->add_sample(common->datasize, stime);
|
||||
}
|
||||
|
||||
/*
|
||||
// Track unique devices
|
||||
if (globalreg->timestamp.tv_sec != chan_channel->last_device_sec) {
|
||||
chan_channel->last_device_sec = globalreg->timestamp.tv_sec;
|
||||
chan_channel->seen_device_map.clear();
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
chan_channel->seen_device_map[common->device] = true;
|
||||
|
||||
chan_channel->get_device_rrd()->add_sample(
|
||||
chan_channel->seen_device_map.size(),
|
||||
globalreg->timestamp.tv_sec);
|
||||
*/
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
/*
|
||||
This file is part of Kismet
|
||||
|
||||
Kismet is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Kismet is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Kismet; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __CHANNELTRACKER_V2_H__
|
||||
#define __CHANNELTRACKER_V2_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "globalregistry.h"
|
||||
#include "kis_mutex.h"
|
||||
#include "trackedelement.h"
|
||||
#include "kis_net_microhttpd.h"
|
||||
#include "devicetracker_component.h"
|
||||
#include "packetchain.h"
|
||||
#include "timetracker.h"
|
||||
|
||||
// Can appear in the list as either a numerical frequency or a named
|
||||
// channel
|
||||
class Channeltracker_V2_Channel : public tracker_component, public SharedGlobalData {
|
||||
public:
|
||||
Channeltracker_V2_Channel() :
|
||||
tracker_component() {
|
||||
register_fields();
|
||||
reserve_fields(NULL);
|
||||
}
|
||||
|
||||
Channeltracker_V2_Channel(int in_id) :
|
||||
tracker_component(in_id) {
|
||||
register_fields();
|
||||
reserve_fields(NULL);
|
||||
|
||||
// last_device_sec = 0;
|
||||
}
|
||||
|
||||
Channeltracker_V2_Channel(int in_id, std::shared_ptr<TrackerElementMap> e) :
|
||||
tracker_component(in_id) {
|
||||
|
||||
register_fields();
|
||||
reserve_fields(e);
|
||||
|
||||
// last_device_sec = 0;
|
||||
}
|
||||
|
||||
virtual uint32_t get_signature() const override {
|
||||
return Adler32Checksum("Channeltracker_V2_Channel");
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<TrackerElement> clone_type() override {
|
||||
using this_t = std::remove_pointer<decltype(this)>::type;
|
||||
auto dup = std::unique_ptr<this_t>(new this_t());
|
||||
return std::move(dup);
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<TrackerElement> clone_type(int in_id) override {
|
||||
using this_t = std::remove_pointer<decltype(this)>::type;
|
||||
auto dup = std::unique_ptr<this_t>(new this_t(in_id));
|
||||
return std::move(dup);
|
||||
}
|
||||
|
||||
__Proxy(channel, std::string, std::string, std::string, channel);
|
||||
__Proxy(frequency, double, double, double, frequency);
|
||||
|
||||
typedef kis_tracked_rrd<> uint64_rrd;
|
||||
|
||||
__ProxyTrackable(packets_rrd, uint64_rrd, packets_rrd);
|
||||
__ProxyTrackable(data_rrd, uint64_rrd, data_rrd);
|
||||
__ProxyTrackable(device_rrd,uint64_rrd, device_rrd);
|
||||
|
||||
__ProxyTrackable(signal_data, kis_tracked_signal_data, signal_data);
|
||||
|
||||
/*
|
||||
// C++-domain map of devices we've seen in the last second for computing if we
|
||||
// increase the RRD record
|
||||
map<mac_addr, bool> seen_device_map;
|
||||
time_t last_device_sec;
|
||||
*/
|
||||
|
||||
protected:
|
||||
// Timer for updating the device list
|
||||
int timer_id;
|
||||
|
||||
virtual void register_fields() override {
|
||||
tracker_component::register_fields();
|
||||
|
||||
RegisterField("kismet.channelrec.channel", "logical channel", &channel);
|
||||
RegisterField("kismet.channelrec.frequency", "physical frequency", &frequency);
|
||||
RegisterField("kismet.channelrec.packets_rrd", "packet count RRD", &packets_rrd);
|
||||
RegisterField("kismet.channelrec.data_rrd", "byte count RRD", &data_rrd);
|
||||
RegisterField("kismet.channelrec.device_rrd", "active devices RRD", &device_rrd);
|
||||
RegisterField("kismet.channelrec.signal", "signal records", &signal_data);
|
||||
}
|
||||
|
||||
virtual void reserve_fields(std::shared_ptr<TrackerElementMap> e) override {
|
||||
tracker_component::reserve_fields(e);
|
||||
|
||||
// Don't fast-forward the device RRD
|
||||
device_rrd->update_before_serialize(false);
|
||||
}
|
||||
|
||||
// Channel, as string - Logical channels
|
||||
std::shared_ptr<TrackerElementString> channel;
|
||||
|
||||
// Frequency, for collating
|
||||
std::shared_ptr<TrackerElementDouble> frequency;
|
||||
|
||||
// Packets per second RRD
|
||||
std::shared_ptr<kis_tracked_rrd<> > packets_rrd;
|
||||
|
||||
// Data in bytes per second RRD
|
||||
std::shared_ptr<kis_tracked_rrd<> > data_rrd;
|
||||
|
||||
// Devices active per second RRD
|
||||
std::shared_ptr<kis_tracked_rrd<> > device_rrd;
|
||||
|
||||
// Overall signal data. This could in theory be populated by spectrum
|
||||
// analyzers in the future as well.
|
||||
std::shared_ptr<kis_tracked_signal_data> signal_data;
|
||||
|
||||
};
|
||||
|
||||
class Channeltracker_V2 : public tracker_component,
|
||||
public Kis_Net_Httpd_CPPStream_Handler, public LifetimeGlobal,
|
||||
public TimetrackerEvent {
|
||||
public:
|
||||
static std::string global_name() { return "CHANNEL_TRACKER"; }
|
||||
|
||||
static std::shared_ptr<Channeltracker_V2> create_channeltracker(GlobalRegistry *in_globalreg) {
|
||||
std::shared_ptr<Channeltracker_V2> mon(new Channeltracker_V2(in_globalreg));
|
||||
in_globalreg->RegisterLifetimeGlobal(mon);
|
||||
in_globalreg->InsertGlobal(global_name(), mon);
|
||||
return mon;
|
||||
}
|
||||
|
||||
private:
|
||||
Channeltracker_V2(GlobalRegistry *in_globalreg);
|
||||
|
||||
public:
|
||||
virtual ~Channeltracker_V2();
|
||||
|
||||
// HTTP API
|
||||
virtual bool Httpd_VerifyPath(const char *path, const char *method);
|
||||
|
||||
virtual void Httpd_CreateStreamResponse(Kis_Net_Httpd *httpd,
|
||||
Kis_Net_Httpd_Connection *connection,
|
||||
const char *url, const char *method, const char *upload_data,
|
||||
size_t *upload_data_size, std::stringstream &stream);
|
||||
|
||||
// Timetracker API
|
||||
virtual int timetracker_event(int event_id);
|
||||
|
||||
// Update device counts
|
||||
void update_device_counts(std::map<double, unsigned int> in_counts);
|
||||
|
||||
int device_decay;
|
||||
|
||||
protected:
|
||||
kis_recursive_timed_mutex lock;
|
||||
|
||||
std::shared_ptr<Devicetracker> devicetracker;
|
||||
std::shared_ptr<Timetracker> timetracker;
|
||||
|
||||
// Packetchain callback
|
||||
static int PacketChainHandler(CHAINCALL_PARMS);
|
||||
|
||||
// Tracker component
|
||||
virtual void register_fields();
|
||||
|
||||
// Seen channels as string-named channels, so logical channel allocation
|
||||
// per phy
|
||||
std::shared_ptr<TrackerElementStringMap> channel_map;
|
||||
|
||||
// Collapsed frequency information, multi-phy, spec-an, etc
|
||||
std::shared_ptr<TrackerElementDoubleMap> frequency_map;
|
||||
|
||||
// Channel/freq content
|
||||
int channel_entry_id;
|
||||
|
||||
int pack_comp_l1data, pack_comp_devinfo, pack_comp_common, pack_comp_device;
|
||||
|
||||
int timer_id;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue