Packages: Rename kismet -> kismet-hak5

pull/6/head
Foxtrot 2019-07-06 21:00:53 +01:00
parent 35b61da827
commit 38d3e37456
625 changed files with 368032 additions and 1 deletions

View File

@ -0,0 +1,401 @@
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

View File

@ -0,0 +1,347 @@
** 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.

View File

@ -0,0 +1,618 @@
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

View File

@ -0,0 +1,68 @@
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

View File

@ -0,0 +1,183 @@
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

View File

@ -0,0 +1,21 @@
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
```

View File

@ -0,0 +1 @@
2019-04-GIT

View File

@ -0,0 +1,853 @@
/*
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;
}

View File

@ -0,0 +1,437 @@
/*
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)", &timestamp);
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

View File

@ -0,0 +1,459 @@
#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

View File

@ -0,0 +1,111 @@
/*
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);
}

View File

@ -0,0 +1,134 @@
/*
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

View File

@ -0,0 +1,434 @@
/* 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

View File

@ -0,0 +1,31 @@
/*
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

View File

@ -0,0 +1,82 @@
/*
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;
}

View File

@ -0,0 +1,45 @@
/*
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

View File

@ -0,0 +1,615 @@
/*
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", &current_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;
}

View File

@ -0,0 +1,39 @@
/*
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

View File

@ -0,0 +1,29 @@
/*
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();
}

View File

@ -0,0 +1,112 @@
/*
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

View File

@ -0,0 +1,70 @@
/*
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));
}

View File

@ -0,0 +1,55 @@
/*
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

View File

@ -0,0 +1,598 @@
/*
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;
}

View File

@ -0,0 +1,443 @@
/*
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

View File

@ -0,0 +1,822 @@
/*
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

View File

@ -0,0 +1,527 @@
"""
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

View File

@ -0,0 +1,18 @@
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

View File

@ -0,0 +1,84 @@
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

View File

@ -0,0 +1,27 @@
#!/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)

View File

@ -0,0 +1,16 @@
#!/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'],
)

View File

@ -0,0 +1,427 @@
/*
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;
}

View File

@ -0,0 +1,713 @@
/*
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;
}

View File

@ -0,0 +1,30 @@
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)))

View File

@ -0,0 +1,4 @@
# Kismet Linux Bluetooth
Uses the bluez management socket API to initiate scans for devices

View File

@ -0,0 +1,933 @@
/*
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;
}

View File

@ -0,0 +1,120 @@
/*
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

View File

@ -0,0 +1,53 @@
/*
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

View File

@ -0,0 +1,20 @@
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

View File

@ -0,0 +1,149 @@
/*
*
* 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 */

View File

@ -0,0 +1,172 @@
/*
*
* 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 */

View File

@ -0,0 +1,404 @@
/*
*
* 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 */

View File

@ -0,0 +1,162 @@
/*
*
* 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 */

View File

@ -0,0 +1,69 @@
/*
*
* 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

View File

@ -0,0 +1,242 @@
/*
*
* 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 */

View File

@ -0,0 +1,85 @@
/*
*
* 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 */

View File

@ -0,0 +1,279 @@
/*
*
* 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 */

View File

@ -0,0 +1,926 @@
/*
* 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];
}

View File

@ -0,0 +1,99 @@
/*
*
* 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 */

View File

@ -0,0 +1,62 @@
/*
*
* 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 */

View File

@ -0,0 +1,542 @@
/*
*
* 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 */

View File

@ -0,0 +1,634 @@
/*
*
* 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 */

View File

@ -0,0 +1,181 @@
/*
*
* 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 */

View File

@ -0,0 +1,38 @@
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

View File

@ -0,0 +1,830 @@
/*
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 */

View File

@ -0,0 +1,158 @@
/*
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

View File

@ -0,0 +1,183 @@
/*
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;
}

View File

@ -0,0 +1,46 @@
/*
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

View File

@ -0,0 +1,722 @@
/*
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

View File

@ -0,0 +1,189 @@
/*
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

View File

@ -0,0 +1,121 @@
/*
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

View File

@ -0,0 +1,58 @@
/*
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

View File

@ -0,0 +1,30 @@
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)))

View File

@ -0,0 +1,720 @@
/*
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;
}

View File

@ -0,0 +1,59 @@
/*
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

View File

@ -0,0 +1,40 @@
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)))

View File

@ -0,0 +1,808 @@
/*
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;
}

View File

@ -0,0 +1,391 @@
/*
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;
}

View File

@ -0,0 +1,458 @@
"""
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

View File

@ -0,0 +1,21 @@
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

View File

@ -0,0 +1,70 @@
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

View File

@ -0,0 +1,30 @@
#!/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)

View File

@ -0,0 +1,30 @@
#!/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)

View File

@ -0,0 +1,16 @@
#!/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'],
)

View File

@ -0,0 +1,668 @@
#!/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

View File

@ -0,0 +1,25 @@
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

View File

@ -0,0 +1,66 @@
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

View File

@ -0,0 +1,30 @@
#!/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)

View File

@ -0,0 +1,30 @@
#!/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)

View File

@ -0,0 +1,18 @@
#!/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']},
)

View File

@ -0,0 +1,451 @@
#!/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

View File

@ -0,0 +1,24 @@
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

View File

@ -0,0 +1,68 @@
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.

View File

@ -0,0 +1,30 @@
#!/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)

View File

@ -0,0 +1,30 @@
#!/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)

View File

@ -0,0 +1,16 @@
#!/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'],
)

View File

@ -0,0 +1,360 @@
/*
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;
}
}

View File

@ -0,0 +1,108 @@
/*
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

View File

@ -0,0 +1,302 @@
/*
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;
}

Some files were not shown because too many files have changed in this diff Show More