pax_global_header00006660000000000000000000000064115237370030014513gustar00rootroot0000000000000052 comment=a8766f8ec735a1cbd7ba4bbd1b759ed6e835f117 horst-3.0/000077500000000000000000000000001152373700300125145ustar00rootroot00000000000000horst-3.0/.gitignore000066400000000000000000000000171152373700300145020ustar00rootroot00000000000000.build_* horst horst-3.0/ChangeLog000066400000000000000000000041631152373700300142720ustar00rootroot000000000000002007-12-26 (2.0-rc1) Bruno Randolf (br1@einfach.org) * added radiotap header support and automatic detection of the header format used by the driver (prism2 or radiotap). * added IBSS split detection: warn when one ESSID (name) is announced with different BSSIDs in beacons from different nodes in IBSS mode. very useful for debugging IBSS problems. * new ESSID window: list all known ESSIDs and all stations which announce the ESSID in their beacons including the TSF timestamp for easier IBSS split analysis. * new history window: display Signal/Noise/Rate graph * new packet statistics window: display the percentage of different packet types and physical rates and other packet statistics. * improved filtering framework: allow filtering by packet types, MAC addresses, BSSID. * added duration calculation: "AirTime" to estimate the pyhsical usage of the channel. * optimized screen updates and buffering: to save CPU time and to avoid loosing packets. added -w and -d options for fine grained control of display update and sleep intervals. -b option to change the buffer size (it's quite large by default now). * much more complete and improved 802.11 packet parsing. * better node timeout handling, using linked lists. -t command line option to specify node timeout. * sort node list by SNR, age, BSSID or channel. * -o option to write packet infos into a text file. * initial (primitive) B.A.T.M.A.N support. * various smaller improvements, fixes, cleanups and beautifications. 2007-07-20 Sven-Ola aet gmx.de * Added -e macaddr filter switch 2007-01-15 Anon (Sven-Ola: I cannot remember whos sending this) * Added remote capability. Start on one WRT using -q then listen on other WRT with -p [not quite true...] 2006-10-12 Robert Schuster (robertschuster@fsfe.org) * various changes to output (requested by Horst :) ) * fixed some includes (to compile with (k)ubunut) * added version and build date to main window 2006-10-12 Sven-Ola aet gmx.de * Unfixed some includes. the necesary include addon is required to fix (k)ubunto ip.h whoes but breaks build elsewhere horst-3.0/LICENSE000066400000000000000000000431331152373700300135250ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, 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 Library 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. Copyright (C) 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 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. , 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 Library General Public License instead of this License. horst-3.0/Makefile000066400000000000000000000050731152373700300141610ustar00rootroot00000000000000# horst - Highly Optimized Radio Scanning Tool # # Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. NAME=horst DEBUG=0 PCAP=0 OBJS=main.o capture$(if $(filter 1,$(PCAP)),-pcap).o protocol_parser.o \ network.o wext.o node.o essid.o channel.o \ util.o ieee80211_util.o listsort.o average.o \ display.o display-main.o display-filter.o display-help.o \ display-statistics.o display-essid.o display-history.o \ display-spectrum.o display-channel.o LIBS=-lncurses -lm CFLAGS+=-Wall -DDO_DEBUG=$(DEBUG) -g ifeq ($(PCAP),1) CFLAGS+=-DPCAP LIBS+=-lpcap endif buildstamp=.build_debug$(DEBUG)pcap$(PCAP) all: $(buildstamp) $(NAME) # include dependencies average.o: average.h util.h capture.o: capture.h util.h capture-pcap.o: capture.h util.h channel.o: main.h util.h ieee80211_util.h wext.h display.o: display.h main.h ieee80211.h display-channel.o: display.h main.h display-essid.o: display.h main.h util.h display-filter.o: display.h main.h util.h ieee80211.h display-help.o: display.h main.h util.h display-history.o: display.h main.h util.h display-main.o: display.h main.h util.h ieee80211.h olsr_header.h listsort.h display-spectrum.o: display.h main.h util.h display-statistics.o: display.h main.h util.h essid.o: main.h util.h ieee80211.h ieee80211_util.o: ieee80211.h ieee80211_radiotap.h ieee80211_util.h main.h \ util.h listsort.o: list.h listsort.h main.o: protocol_parser.h display.h network.h main.h capture.h util.h \ ieee80211.h ieee80211_util.h wext.h average.h node.o: main.h ieee80211.h util.h network.o: main.h util.h network.h protocol_parser.o: prism_header.h ieee80211_radiotap.h ieee80211.h \ ieee80211_util.h olsr_header.h batman_header.h protocol_parser.h \ main.h util.h util.o: util.h ieee80211.h wext.o: wext.h util.h $(NAME): $(OBJS) $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) clean: -rm -f *.o *~ -rm -f $(NAME) -rm -f .build_* $(buildstamp): make clean touch $@ horst-3.0/README000066400000000000000000000071421152373700300134000ustar00rootroot00000000000000HORST - Horsts OLSR Radio Scanning Tool (or) HORST - Highly Optimized Radio Scanning Tool -------------------------------------------- Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.org) Licensed under the GNU Public License (GPL) V2 = Overview = "horst" is a scanning and analysis tool for IEEE802.11 wireless ad-hoc (IBSS) networks and the OLSR mesh routing protocol. it can be used discover the best OLSR nodes in the neighbourhood, to optimize antenna positions and to discover problems in the mesh network. = Description = with the usual wireless tools like iwconfig and iwspy (and even kismet) it is hard to measure the received signal strength (SNR or RSSI) for each of the *different* nodes which form an ad-hoc network, since they all treat the whole IBSS as one. this information however is very important for setting up, debugging and optimizing wireless mesh networks. "horst" aims to fill this gap and lists each single node of an ad-hoc network seperately, showing the signal strength (SNR) of the last received packet. this way you can see which nodes are part of a specific ad-hoc cell (BSSID), discover problems with ad-hoc cell merging ("cell splitting" - a problem of many wlan drivers), which of the nodes send OLSR packets, wether they use the OLSR link quality exension, how many neighbors they see, etc. to do this, it uses the monitor mode including prism2 or radiotap headers (for the signal strength information) of the wlan cards and listens to all packets which come in the wireless interface. these packets are scanned for OLSR traffic, summarized by the MAC address of the sending node, and displayed in a simple text (ncurses) interface. "horst" should work with any wlan card which can do monitor mode, with either "prism2" or "radiotap" headers. = Usage = you have to put your card in monitor mode and set the channel manually before you start the tool (it does not rotate channels like kismet): 1.) put card in monitor mode: hostap: # iwconfig wlan0 mode monitor madwifi: # wlanconfig wlan0 create wlandev wifi0 wlanmode monitor 2.) for hostap: enable prism headers in monitor mode # iwpriv wlan0 monitor_type 1 3.) tune to a channel # iwconfig wlan0 channel 10 # ifconfig wlan0 up 4.) start tool # ./horst 5.) see options # ./horst --help = Interpreting the Output = we try to fit a lot of mostly binary or numeric information to a tiny screen, so at first it will look confusing ;) the upper box shows a summary of the information we gathered for each MAC address (node) we saw, each one in a row: IP IP address (if available) SNR Signal/Noise ratio of the LAST packet SOURCE MAC address of the source BSSID The BSSID this MAC is on LQ Marked when OLSR Link Quality (LQ) Extension is used GW Marked when this OLSR Node probably knows a default gateway NEIGH Number of Neighbours OLSR Number of OLSR Pakets received COUNT Number of all packets received TSF The high part of the TSF the lower box dumps all received packets and shows some information for it: Sig Signal in dBm Noi Noise in dBm SOURCE MAC Address of the Sender BSSID The BSSID the Sender belongs to TYPE Packet Type INFO Additional packet information, depending on type the lower right box shows the status and displays the SNR of the last packet graphically with a bar. = Building = "horst" is just a simple tool, so "libncurses" is the only requirement (be sure to install it's header files too). therefore building is as simple as typing: $ make for debugging you can use $ make DEBUG=1 = Contributors = Thanks to the following persons for contributions: Horst Krause Sven-Ola Tuecke Robert Schuster Jonathan Guerin David Rowe horst-3.0/TODO000066400000000000000000000042261152373700300132100ustar00rootroot00000000000000----- TODO: ----- * better batman support * OLSR ETX auswertung * IP auswertung * sig/noise WRT * detaildenster sortiert nach ESSID ----------------- feature requests: ----------------- * FCS errors checken * batman layer 2 ethertype 0x0842 --- > WEITERE OPTIONEN, (braucht ein tmp. eingabe-feld, zb. im header) > evt. als [IP:], dann untermenue: > - [k: keep] eintrag nach time-out in der anzeige halten, markiert m."?". > - [u: up ] mit der man einzelne IPs 'nach-oben' holen kann, > wichtig für schwache nodes, die sonst bei langer liste > nach unten aus dem sichtbaren display gedrängt würden. > - [d: del] ausgewählte IPs aus der anzeige filtern. --- sound output --- > ist es machbar bei rel. kleinem maßstab das fenster um 90° nach rechts zu > drehen und eine spalte IP u/o. MAC, (evt. togglebar mit "i","m") hinzu zu > fügen, damit man den ursprung der packets identifizieren kann. > ausserdem eine LQ/NQ-spalte hinzu zu fügen, > damit man von jedem packet auf einen blick die werte beisammen hat: > > IP/MAC____________T_RT__LQ/NL__NOI & SIG & SIG.max [10dB] > 10..90..80..70..60..50..40. > 111.222.333.444or A 1 86/92 xxx----------- | > MM:MM:AA:AA:CC:CC I 54 214/183 xxxx----- | > #soll bat-count = #/255 sein. --- *CH_IP______________SI/N0_ESSID_______________BSSID_____________MAC______________pT_NNLG_.TSF_ -06 111.222.333.444 82/92 'lotte' bb:ss:ss:ii:dd:00 MM:MM:AA:AA:CC:CC A ----.0003a 10 'olsr.freifunk.net' *** ! SPLIT ! *** # hier könnte es blinken! / 111.222.333.444 84/93 bb:ss:ss:ii:dd:00 MM:MM:AA:AA:CC:CC I ----.fffde \ 103.111.222.333 72/96 02:ca:ff:ee:ba:be MM:MM:AA:AA:CC:CCxI 12LG.fffff - 104.111.222.333 .. .. .. .. .. .. .. .. .. .. .. .. .. ..oI .......... / 105.111.222.333 .. .. .. .. .. .. .. .. .. .. .. ..bI .......... /13 111.222.333.444 78/95 'NETGEAR' bb:ss:ss:ii:dd:00 mm:mm:aa:aa:cc:cc A----.0002b =============================================================================================== horst-3.0/average.c000066400000000000000000000035301152373700300142730ustar00rootroot00000000000000/* * lib/average.c * * This source code is licensed under the GNU General Public License, * Version 2. See the file COPYING for more details. */ #include #include "average.h" #include "util.h" /** * DOC: Exponentially Weighted Moving Average (EWMA) * * These are generic functions for calculating Exponentially Weighted Moving * Averages (EWMA). We keep a structure with the EWMA parameters and a scaled * up internal representation of the average value to prevent rounding errors. * The factor for scaling up and the exponential weight (or decay rate) have to * be specified thru the init fuction. The structure should not be accessed * directly but only thru the helper functions. */ /** * ewma_init() - Initialize EWMA parameters * @avg: Average structure * @factor: Factor to use for the scaled up internal value. The maximum value * of averages can be ULONG_MAX/(factor*weight). For performance reasons * factor has to be a power of 2. * @weight: Exponential weight, or decay rate. This defines how fast the * influence of older values decreases. For performance reasons weight has * to be a power of 2. * * Initialize the EWMA parameters for a given struct ewma @avg. */ void ewma_init(struct ewma *avg, unsigned long factor, unsigned long weight) { if(!is_power_of_2(weight) || !is_power_of_2(factor)) error(1, 0, "weight and factor have to be a power of two!"); avg->weight = ilog2(weight); avg->factor = ilog2(factor); avg->internal = 0; } /** * ewma_add() - Exponentially weighted moving average (EWMA) * @avg: Average structure * @val: Current value * * Add a sample to the average. */ struct ewma *ewma_add(struct ewma *avg, unsigned long val) { avg->internal = avg->internal ? (((avg->internal << avg->weight) - avg->internal) + (val << avg->factor)) >> avg->weight : (val << avg->factor); return avg; } horst-3.0/average.h000066400000000000000000000012111152373700300142720ustar00rootroot00000000000000#ifndef _LINUX_AVERAGE_H #define _LINUX_AVERAGE_H /* Exponentially weighted moving average (EWMA) */ /* For more documentation see average.c */ struct ewma { unsigned long internal; unsigned long factor; unsigned long weight; }; extern void ewma_init(struct ewma *avg, unsigned long factor, unsigned long weight); extern struct ewma *ewma_add(struct ewma *avg, unsigned long val); /** * ewma_read() - Get average value * @avg: Average structure * * Returns the average value held in @avg. */ static inline unsigned long ewma_read(const struct ewma *avg) { return avg->internal >> avg->factor; } #endif /* _LINUX_AVERAGE_H */ horst-3.0/batman_header.h000066400000000000000000000026051152373700300154420ustar00rootroot00000000000000/* copied from batman batman.h */ /* * Copyright (C) 2006 B.A.T.M.A.N. contributors: * Thomas Lopatic, Corinna 'Elektra' Aichele, Axel Neumann, Marek Lindner * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License 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. * * 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 * */ #ifndef _BATMAN_BATMAN_H #define _BATMAN_BATMAN_H #define BAT_PORT 4305 #define BAT_UNIDIRECTIONAL 0x80 #define BAT_DIRECTLINK 0x40 #define BAT_ADDR_STR_LEN 16 #define BAT_TQ_MAX_VALUE 255 struct bat_packet { uint32_t orig; uint32_t old_orig; uint8_t flags; /* 0x80: UNIDIRECTIONAL link, 0x40: DIRECTLINK flag, ... */ uint8_t ttl; uint16_t seqno; uint8_t gwflags; /* flags related to gateway functions: gateway class */ uint8_t version; /* batman version field */ uint8_t tq; } __attribute__((packed)); #endif horst-3.0/capture-pcap.c000066400000000000000000000044611152373700300152510ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.org) * Copyright (C) 2007 Sven-Ola Tuecke * * 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. */ #include #include #include #include "capture.h" #include "util.h" void __attribute__ ((format (printf, 1, 2))) printlog(const char *fmt, ...); #define PCAP_TIMEOUT 200 static unsigned char* pcap_buffer; static size_t pcap_bufsize; static pcap_t *pcap_fp = NULL; void handler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) { *((int *)user) = h->len; if (pcap_bufsize < h->len) { printlog("ERROR: Buffer(%d) too small for %d bytes", (int)pcap_bufsize, h->len); *((int *)user) = pcap_bufsize; } memmove(pcap_buffer, bytes, *((int *)user)); } int open_packet_socket(char* devname, size_t bufsize, int recv_buffer_size) { char error[PCAP_ERRBUF_SIZE]; pcap_fp = pcap_open_live(devname, bufsize, 1, PCAP_TIMEOUT, error); if (pcap_fp == NULL) { fprintf(stderr, "Couldn't open pcap device: %s\n", error); return -1; } return pcap_fileno(pcap_fp); } int device_get_arptype(int fd, char* ifname) { if (pcap_fp != NULL) { switch (pcap_datalink(pcap_fp)) { case DLT_IEEE802_11_RADIO: return 803; case DLT_PRISM_HEADER: return 802; default: return 801; } } return -1; } int recv_packet(int fd, unsigned char* buffer, size_t bufsize) { int ret = 0; pcap_buffer = buffer; pcap_bufsize = bufsize; if (0 == pcap_dispatch(pcap_fp, 1, handler, (u_char *)&ret)) return -1; return ret; } void close_packet_socket(int fd, char* ifname) { if (pcap_fp != NULL) pcap_close(pcap_fp); } horst-3.0/capture.c000066400000000000000000000075601152373700300143330ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include "capture.h" #include "util.h" static int device_index(int fd, const char *devname) { struct ifreq req; strncpy(req.ifr_name, devname, IFNAMSIZ); req.ifr_addr.sa_family = AF_INET; if (ioctl(fd, SIOCGIFINDEX, &req) < 0) err(1, "Interface %s not found", devname); if (req.ifr_ifindex < 0) err(1, "Interface %s not found", devname); DEBUG("index %d\n", req.ifr_ifindex); return req.ifr_ifindex; } static void device_promisc(int fd, const char *devname, int on) { struct ifreq req; strncpy(req.ifr_name, devname, IFNAMSIZ); req.ifr_addr.sa_family = AF_INET; if (ioctl(fd, SIOCGIFFLAGS, &req) < 0) err(1, "Could not get device flags for %s", devname); /* put interface up in any case */ req.ifr_flags |= IFF_UP; if (on) req.ifr_flags |= IFF_PROMISC; else req.ifr_flags &= ~IFF_PROMISC; if (ioctl(fd, SIOCSIFFLAGS, &req) < 0) err(1, "Could not set promisc mode for %s", devname); } /* * Get the hardware type of the given interface as ARPHRD_xxx constant. */ int device_get_arptype(int fd, char* ifname) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) err(1, "Could not get arptype"); DEBUG("ARPTYPE %d\n", ifr.ifr_hwaddr.sa_family); return ifr.ifr_hwaddr.sa_family; } static void set_receive_buffer(int fd, int sockbufsize) { int ret; /* the maximum allowed value is set by the rmem_max sysctl */ FILE* PF = fopen("/proc/sys/net/core/rmem_max", "w"); fprintf(PF, "%d", sockbufsize); fclose(PF); ret = setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &sockbufsize, sizeof(sockbufsize)); if (ret != 0) err(1, "setsockopt failed"); #if DO_DEBUG socklen_t size = sizeof(sockbufsize); sockbufsize = 0; ret = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &sockbufsize, &size); if (ret != 0) err(1, "getsockopt failed"); DEBUG("socket receive buffer size %d\n", sockbufsize); #endif } int open_packet_socket(char* devname, size_t bufsize, int recv_buffer_size) { int ret; int mon_fd; int ifindex; struct sockaddr_ll sall; mon_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (mon_fd < 0) err(1, "Could not create packet socket"); /* bind only to one interface */ ifindex = device_index(mon_fd, devname); memset(&sall, 0, sizeof(struct sockaddr_ll)); sall.sll_ifindex = ifindex; sall.sll_family = AF_PACKET; sall.sll_protocol = htons(ETH_P_ALL); ret = bind(mon_fd, (struct sockaddr*)&sall, sizeof(sall)); if (ret != 0) err(1, "bind failed"); device_promisc(mon_fd, devname, 1); if (recv_buffer_size) set_receive_buffer(mon_fd, recv_buffer_size); return mon_fd; } inline int recv_packet(int fd, unsigned char* buffer, size_t bufsize) { return recv(fd, buffer, bufsize, MSG_DONTWAIT); } void close_packet_socket(int fd, char* ifname) { if (fd > 0) { device_promisc(fd, ifname, 0); close(fd); } } horst-3.0/capture.h000066400000000000000000000021631152373700300143320ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _CAPTURE_H_ #define _CAPTURE_H_ int open_packet_socket(char* devname, size_t bufsize, int recv_buffer_size); int recv_packet(int fd, unsigned char* buffer, size_t bufsize); void close_packet_socket(int fd, char* ifname); int device_get_arptype(int fd, char* ifname); #endif // _CAPTURE_H_ horst-3.0/channel.c000066400000000000000000000054001152373700300142670ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "main.h" #include "util.h" #include "ieee80211_util.h" #include "wext.h" static struct timeval last_channelchange; extern int mon; /* monitoring socket */ int change_channel(int idx) { if (wext_set_freq(mon, conf.ifname, channels[idx].freq) == 0) { printlog("ERROR: could not set channel %d", channels[idx].chan); return 0; } conf.current_channel = idx; return 1; } int auto_change_channel(int mon) { int new_chan; int ret = 1; int start_chan; if (the_time.tv_sec == last_channelchange.tv_sec && (the_time.tv_usec - last_channelchange.tv_usec) < conf.channel_time) return 0; /* too early */ if (conf.do_change_channel) { start_chan = new_chan = conf.current_channel; do { new_chan = new_chan + 1; if (new_chan >= conf.num_channels || new_chan >= MAX_CHANNELS || (conf.channel_max && new_chan >= conf.channel_max)) new_chan = 0; ret = change_channel(new_chan); /* try setting different channels in case we get errors only * on some channels (e.g. ipw2200 reports channel 14 but cannot * be set to use it). stop if we tried all channels */ } while (ret != 1 && new_chan != start_chan); } last_channelchange = the_time; return ret; } void init_channels(void) { int i; for (i = 0; i < conf.num_channels && i < MAX_CHANNELS; i++) { INIT_LIST_HEAD(&spectrum[i].nodes); ewma_init(&spectrum[i].signal_avg, 1024, 8); ewma_init(&spectrum[i].durations_avg, 1024, 8); } } int find_channel_index(int c) { int i = -1; for (i = 0; i < conf.num_channels && i < MAX_CHANNELS; i++) if (channels[i].chan == c) return i; return -1; } void get_current_channel(int mon) { int freq, ch; /* get current channel & map to our channel array */ freq = wext_get_freq(mon, conf.ifname); if (freq == 0) return; ch = ieee80211_frequency_to_channel(freq); ch = find_channel_index(ch); if (ch >= 0) conf.current_channel = ch; DEBUG("***%d\n", conf.current_channel); } horst-3.0/display-channel.c000066400000000000000000000045771152373700300157500ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /******************* FILTER *******************/ #include #include "display.h" #include "main.h" #include "network.h" void update_channel_win(WINDOW *win) { box(win, 0 , 0); print_centered(win, 0, 39, " Channel Settings "); mvwprintw(win, 2, 2, "a: [%c] Automatically change channel", conf.do_change_channel ? '*' : ' '); mvwprintw(win, 3, 2, "d: Channel dwell time: %d ms ", conf.channel_time/1000); mvwprintw(win, 4, 2, "u: Upper channel limit: %d ", conf.channel_max); mvwprintw(win, 6, 2, "m: Manually change channel: %d ", CONF_CURRENT_CHANNEL); print_centered(win, 9, 39, "[ Press key or ENTER ]"); wrefresh(win); } int channel_input(WINDOW *win, int c) { char buf[6]; int x; switch (c) { case 'a': case 'A': conf.do_change_channel = conf.do_change_channel ? 0 : 1; break; case 'd': case 'D': echo(); curs_set(1); mvwgetnstr(win, 3, 25, buf, 6); curs_set(0); noecho(); sscanf(buf, "%d", &x); conf.channel_time = x*1000; break; case 'u': case 'U': echo(); curs_set(1); mvwgetnstr(win, 4, 26, buf, 6); curs_set(0); noecho(); sscanf(buf, "%d", &x); conf.channel_max = x; break; case 'm': case 'M': conf.do_change_channel = 0; echo(); curs_set(1); mvwgetnstr(win, 6, 30, buf, 2); curs_set(0); noecho(); sscanf(buf, "%d", &x); x = find_channel_index(x); if (x >= 0) { if (!conf.serveraddr) change_channel(x); else conf.current_channel = x; } break; default: return 0; /* didn't handle input */ } net_send_channel_config(); update_channel_win(win); return 1; } horst-3.0/display-essid.c000066400000000000000000000045601152373700300154370ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /******************* ESSID *******************/ #include #include "display.h" #include "main.h" #include "util.h" void update_essid_win(WINDOW *win) { int i; int line = 1; struct essid_info* e; struct node_info* n; werase(win); wattron(win, WHITE); wattroff(win, A_BOLD); box(win, 0 , 0); print_centered(win, 0, COLS, " ESSIDs "); mvwprintw(win, line++, 3, "NO. MODE SOURCE (BSSID) TSF (BINT) CH SNR E IP"); list_for_each_entry(e, &essids.list, list) { if (line > LINES-3) break; wattron(win, WHITE | A_BOLD); mvwprintw(win, line, 2, "ESSID '%s'", e->essid ); if (e->split > 0) { wattron(win, RED); wprintw(win, " *** SPLIT ***"); } else wattron(win, GREEN); line++; i = 1; list_for_each_entry(n, &e->nodes, essid_nodes) { if (line > LINES-3) break; if (n->last_seen > (the_time.tv_sec - conf.node_timeout / 2)) wattron(win, A_BOLD); else wattroff(win, A_BOLD); mvwprintw(win, line, 3, "%2d. %s %s", i++, n->wlan_mode == WLAN_MODE_AP ? "AP " : "IBSS", ether_sprintf(n->last_pkt.wlan_src)); wprintw(win, " (%s)", ether_sprintf(n->wlan_bssid)); wprintw(win, " %016llx", n->wlan_tsf); wprintw(win, " (%d)", n->wlan_bintval); if (n->wlan_bintval < 1000) wprintw(win, " "); wprintw(win, " %2d", n->wlan_channel); wprintw(win, " %2ddB", n->last_pkt.phy_snr); wprintw(win, " %s", n->wlan_wep ? "W" : " "); if (n->pkt_types & PKT_TYPE_IP) wprintw(win, " %s", ip_sprintf(n->ip_src)); line++; } } wnoutrefresh(win); } horst-3.0/display-filter.c000066400000000000000000000161111152373700300156100ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /******************* FILTER *******************/ #include #include "display.h" #include "main.h" #include "util.h" #include "ieee80211.h" #include "network.h" #define CHECKED(_x) (conf.filter_pkt & (_x)) ? '*' : ' ' #define CHECK_ETHER(_mac) MAC_NOT_EMPTY(_mac) ? '*' : ' ' #define CHECK_FILTER_EN(_i) conf.filtermac_enabled[_i] ? '*' : ' ' #define MAC_COL 30 #define FILTER_MAX 25 void update_filter_win(WINDOW *win) { int l, i; box(win, 0 , 0); print_centered(win, 0, 57, " Edit Packet Filter "); mvwprintw(win, 2, 2, "Show these Packet Types"); l = 4; wattron(win, get_packet_type_color(IEEE80211_FTYPE_MGMT)); wattron(win, A_BOLD); mvwprintw(win, l++, 2, "m: [%c] MANAGEMENT FRAMES", CHECKED(PKT_TYPE_MGMT)); wattroff(win, A_BOLD); mvwprintw(win, l++, 2, "b: [%c] Beacons", CHECKED(PKT_TYPE_BEACON)); mvwprintw(win, l++, 2, "p: [%c] Probe Req/Resp", CHECKED(PKT_TYPE_PROBE)); mvwprintw(win, l++, 2, "a: [%c] Association", CHECKED(PKT_TYPE_ASSOC)); mvwprintw(win, l++, 2, "u: [%c] Authentication", CHECKED(PKT_TYPE_AUTH)); l++; wattron(win, get_packet_type_color(IEEE80211_FTYPE_CTL)); wattron(win, A_BOLD); mvwprintw(win, l++, 2, "c: [%c] CONTROL FRAMES", CHECKED(PKT_TYPE_CTRL)); wattroff(win, A_BOLD); mvwprintw(win, l++, 2, "r: [%c] CTS/RTS", CHECKED(PKT_TYPE_CTS | PKT_TYPE_RTS)); mvwprintw(win, l++, 2, "k: [%c] ACK", CHECKED(PKT_TYPE_ACK)); l++; wattron(win, get_packet_type_color(IEEE80211_FTYPE_DATA)); wattron(win, A_BOLD); mvwprintw(win, l++, 2, "d: [%c] DATA FRAMES", CHECKED(PKT_TYPE_DATA)); wattroff(win, A_BOLD); mvwprintw(win, l++, 2, "n: [%c] Null Data", CHECKED(PKT_TYPE_NULL)); mvwprintw(win, l++, 2, "R: [%c] ARP", CHECKED(PKT_TYPE_ARP)); mvwprintw(win, l++, 2, "P: [%c] ICMP/PING", CHECKED(PKT_TYPE_ICMP)); mvwprintw(win, l++, 2, "I: [%c] IP", CHECKED(PKT_TYPE_IP)); mvwprintw(win, l++, 2, "U: [%c] UDP", CHECKED(PKT_TYPE_UDP)); mvwprintw(win, l++, 2, "T: [%c] TCP", CHECKED(PKT_TYPE_TCP)); mvwprintw(win, l++, 2, "O: [%c] OLSR", CHECKED(PKT_TYPE_OLSR)); mvwprintw(win, l++, 2, "B: [%c] BATMAN", CHECKED(PKT_TYPE_BATMAN)); mvwprintw(win, l++, 2, "M: [%c] MeshCruzer", CHECKED(PKT_TYPE_MESHZ)); l = 4; wattron(win, WHITE); wattron(win, A_BOLD); mvwprintw(win, l++, MAC_COL, "BSSID"); wattroff(win, A_BOLD); mvwprintw(win, l++, MAC_COL, "s: [%c] %s", CHECK_ETHER(conf.filterbssid), ether_sprintf(conf.filterbssid)); l++; mvwprintw(win, l++, MAC_COL, "Show only these"); wattron(win, A_BOLD); mvwprintw(win, l++, MAC_COL, "Source MAC ADDRESSES"); wattroff(win, A_BOLD); for (i = 0; i < MAX_FILTERMAC; i++) { mvwprintw(win, l++, MAC_COL, "%d: [%c] %s", i+1, CHECK_FILTER_EN(i), ether_sprintf(conf.filtermac[i])); } l++; wattron(win, A_BOLD); mvwprintw(win, l++, MAC_COL, "o: [%c] All Filters Off", conf.filter_off ? '*' : ' ' ); wattroff(win, A_BOLD); print_centered(win, FILTER_MAX, 57, "[ Press key or ENTER ]"); wrefresh(win); } int filter_input(WINDOW *win, int c) { char buf[18]; int i; switch (c) { case 'm': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_MGMT); if (conf.filter_pkt & PKT_TYPE_MGMT) conf.filter_pkt |= PKT_TYPE_ALL_MGMT; else conf.filter_pkt &= ~PKT_TYPE_ALL_MGMT; break; case 'b': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_BEACON); break; case 'p': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_PROBE); break; case 'a': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_ASSOC); break; case 'u': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_AUTH); break; case 'c': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_CTRL); if (conf.filter_pkt & PKT_TYPE_CTRL) conf.filter_pkt |= PKT_TYPE_ALL_CTRL; else conf.filter_pkt &= ~PKT_TYPE_ALL_CTRL; break; case 'r': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_CTS | PKT_TYPE_RTS); break; case 'k': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_ACK); break; case 'd': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_DATA); if (conf.filter_pkt & PKT_TYPE_DATA) conf.filter_pkt |= PKT_TYPE_ALL_DATA; else conf.filter_pkt &= ~PKT_TYPE_ALL_DATA; break; case 'n': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_NULL); break; case 'R': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_ARP); break; case 'P': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_ICMP); break; case 'I': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_IP); break; case 'U': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_UDP); break; case 'T': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_TCP); break; case 'O': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_OLSR|PKT_TYPE_OLSR_LQ|PKT_TYPE_OLSR_GW); break; case 'B': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_BATMAN); break; case 'M': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_MESHZ); break; case 's': echo(); print_centered(win, FILTER_MAX, 57, "[ Enter new BSSID and ENTER ]"); mvwprintw(win, 5, MAC_COL + 4, ">"); mvwgetnstr(win, 5, MAC_COL + 7, buf, 17); noecho(); convert_string_to_mac(buf, conf.filterbssid); break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': i = c - '1'; if (MAC_NOT_EMPTY(conf.filtermac[i]) && conf.filtermac_enabled[i]) { conf.filtermac_enabled[i] = 0; } else { echo(); print_centered(win, FILTER_MAX, 57, "[ Enter new MAC %d and ENTER ]", i+1); mvwprintw(win, 9 + i, MAC_COL + 4, ">"); mvwgetnstr(win, 9 + i, MAC_COL + 7, buf, 17); noecho(); /* just enable old MAC if user pressed return only */ if (*buf == '\0' && MAC_NOT_EMPTY(conf.filtermac[i])) conf.filtermac_enabled[i] = 1; else { convert_string_to_mac(buf, conf.filtermac[i]); if (MAC_NOT_EMPTY(conf.filtermac[i])) conf.filtermac_enabled[i] = true; } } break; case 'o': conf.filter_off = conf.filter_off ? 0 : 1; break; default: return 0; } /* convenience: */ /* if one of the individual mgmt frames is deselected we dont want to see all mgmt frames */ if ((conf.filter_pkt & PKT_TYPE_ALL_MGMT) != PKT_TYPE_ALL_MGMT) conf.filter_pkt = conf.filter_pkt & ~PKT_TYPE_MGMT; /* same for ctl */ if ((conf.filter_pkt & PKT_TYPE_ALL_CTRL) != PKT_TYPE_ALL_CTRL) conf.filter_pkt = conf.filter_pkt & ~PKT_TYPE_CTRL; /* same for data */ if ((conf.filter_pkt & PKT_TYPE_ALL_DATA) != PKT_TYPE_ALL_DATA) conf.filter_pkt = conf.filter_pkt & ~PKT_TYPE_DATA; /* recalculate filter flag */ conf.do_macfilter = 0; for (i = 0; i < MAX_FILTERMAC; i++) { if (conf.filtermac_enabled[i]) conf.do_macfilter = 1; } net_send_filter_config(); update_filter_win(win); return 1; } horst-3.0/display-help.c000066400000000000000000000042321152373700300152540ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /******************* HELP *******************/ #include #include "display.h" #include "main.h" #include "util.h" void update_help_win(WINDOW *win) { int i, l; char c; werase(win); wattron(win, WHITE); box(win, 0 , 0); print_centered(win, 0, COLS, " Help "); print_centered(win, 2, COLS, "HORST - Horsts OLSR Radio Scanning Tool"); print_centered(win, 3, COLS, "Version " VERSION " (build date " __DATE__ " " __TIME__ ")"); mvwprintw(win, 5, 2, "(C) 2005-2011 Bruno Randolf, Licensed under the GPLv2"); mvwprintw(win, 7, 2, "Known IEEE802.11 Packet Types:"); l = 9; /* this is weird but it works */ mvwprintw(win, l++, 2, "MANAGEMENT FRAMES"); for (i = 0x00; i <= 0xD0; i = i + 0x10) { c = get_packet_type_char(i); if (c != '?') mvwprintw(win, l++, 4, "%c %s", c, get_packet_type_name(i)); } l = 9; mvwprintw(win, l++, 25, "CONTROL FRAMES"); for (i = 0xa4; i <= 0xF4; i = i + 0x10) { c = get_packet_type_char(i); if (c != '?') mvwprintw(win, l++, 27, "%c %s", c, get_packet_type_name(i)); } l = 9; mvwprintw(win, l++, 50, "DATA FRAMES"); for (i = 0x08; i <+ 0xF8; i = i + 0x10) { c = get_packet_type_char(i); if (c != '?') mvwprintw(win, l++, 52, "%c %s", c, get_packet_type_name(i)); } mvwprintw(win, ++l, 2, "For more info read the README or check http://br1.einfach.org/horst/"); wrefresh(win); } horst-3.0/display-history.c000066400000000000000000000075131152373700300160320ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /******************* HISTORY *******************/ #include #include "display.h" #include "main.h" #include "util.h" #define SIGN_POS LINES-17 #define TYPE_POS SIGN_POS+1 #define RATE_POS LINES-2 void update_history_win(WINDOW *win) { int i; int col = COLS-2; int sig, noi = 0, rat; if (col > MAX_HISTORY) col = 4 + MAX_HISTORY; werase(win); wattron(win, WHITE); box(win, 0 , 0); print_centered(win, 0, COLS, " Signal/Noise/Rate History "); mvwhline(win, SIGN_POS, 1, ACS_HLINE, col); mvwhline(win, SIGN_POS+2, 1, ACS_HLINE, col); mvwvline(win, 1, 4, ACS_VLINE, LINES-3); wattron(win, GREEN); mvwprintw(win, 2, 1, "dBm"); mvwprintw(win, normalize_db(30, SIGN_POS - 1) + 1, 1, "-30"); mvwprintw(win, normalize_db(40, SIGN_POS - 1) + 1, 1, "-40"); mvwprintw(win, normalize_db(50, SIGN_POS - 1) + 1, 1, "-50"); mvwprintw(win, normalize_db(60, SIGN_POS - 1) + 1, 1, "-60"); mvwprintw(win, normalize_db(70, SIGN_POS - 1) + 1, 1, "-70"); mvwprintw(win, normalize_db(80, SIGN_POS - 1) + 1, 1, "-80"); mvwprintw(win, normalize_db(90, SIGN_POS - 1) + 1, 1, "-90"); mvwprintw(win, SIGN_POS-1, 1, "-99"); mvwprintw(win, 1, col-6, "Signal"); wattron(win, RED); mvwprintw(win, 2, col-5, "Noise"); wattron(win, CYAN); mvwprintw(win, TYPE_POS, 1, "TYP"); mvwprintw(win, 3, col-11, "Packet Type"); wattron(win, A_BOLD); wattron(win, BLUE); mvwprintw(win, 4, col-4, "Rate"); mvwprintw(win, RATE_POS-12, 1, "54M"); mvwprintw(win, RATE_POS-11, 1, "48M"); mvwprintw(win, RATE_POS-10, 1, "36M"); mvwprintw(win, RATE_POS-9, 1, "24M"); mvwprintw(win, RATE_POS-8, 1, "18M"); mvwprintw(win, RATE_POS-7, 1, "12M"); mvwprintw(win, RATE_POS-6, 1, "11M"); mvwprintw(win, RATE_POS-5, 1, " 9M"); mvwprintw(win, RATE_POS-4, 1, " 6M"); mvwprintw(win, RATE_POS-3, 1, "5.M"); mvwprintw(win, RATE_POS-2, 1, " 2M"); mvwprintw(win, RATE_POS-1, 1, " 1M"); wattroff(win, A_BOLD); i = hist.index - 1; while (col > 4 && hist.signal[i] != 0) { sig = normalize_db(-hist.signal[i], SIGN_POS - 1); if (hist.noise[i]) noi = normalize_db(-hist.noise[i], SIGN_POS - 1); wattron(win, ALLGREEN); mvwvline(win, sig + 1, col, ACS_BLOCK, SIGN_POS - sig - 1); if (hist.noise[i]) { wattron(win, ALLRED); mvwvline(win, noi + 1, col, '=', SIGN_POS - noi -1); } wattron(win, get_packet_type_color(hist.type[i])); mvwprintw(win, TYPE_POS, col, "%c", \ get_packet_type_char(hist.type[i])); if (hist.retry[i]) mvwprintw(win, TYPE_POS+1, col, "r"); switch (hist.rate[i]/2) { case 54: rat = 12; break; case 48: rat = 11; break; case 36: rat = 10; break; case 24: rat = 9; break; case 18: rat = 8; break; case 12: rat = 7; break; case 11: rat = 6; break; case 9: rat = 5; break; case 6: rat = 4; break; case 5: rat = 3; break; case 2: rat = 2; break; case 1: rat = 1; break; default: rat = 0; } wattron(win, A_BOLD); wattron(win, BLUE); mvwvline(win, RATE_POS - rat, col, 'x', rat); wattroff(win, A_BOLD); i--; col--; if (i < 0) i = MAX_HISTORY-1; } wnoutrefresh(win); } horst-3.0/display-main.c000066400000000000000000000336101152373700300152520ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /******************* MAIN / OVERVIEW *******************/ #include #include #include "display.h" #include "main.h" #include "util.h" #include "ieee80211.h" #include "olsr_header.h" #include "listsort.h" static WINDOW *sort_win = NULL; static WINDOW *dump_win = NULL; static WINDOW *list_win = NULL; static WINDOW *stat_win = NULL; static int do_sort = 'n'; /* pointer to the sort function */ static int(*sortfunc)(const struct list_head*, const struct list_head*) = NULL; /* sizes of split window (list_win & status_win) */ static int win_split; static int stat_height; static struct ewma usen_avg; static struct ewma bpsn_avg; /******************* UTIL *******************/ void print_dump_win(const char *str, int refresh) { wattron(dump_win, RED); wprintw(dump_win, str); wattroff(dump_win, RED); if (refresh) wrefresh(dump_win); else wnoutrefresh(dump_win); } /******************* SORTING *******************/ static int compare_nodes_snr(const struct list_head *p1, const struct list_head *p2) { struct node_info* n1 = list_entry(p1, struct node_info, list); struct node_info* n2 = list_entry(p2, struct node_info, list); if (n1->last_pkt.phy_snr > n2->last_pkt.phy_snr) return -1; else if (n1->last_pkt.phy_snr == n2->last_pkt.phy_snr) return 0; else return 1; } static int compare_nodes_time(const struct list_head *p1, const struct list_head *p2) { struct node_info* n1 = list_entry(p1, struct node_info, list); struct node_info* n2 = list_entry(p2, struct node_info, list); if (n1->last_seen > n2->last_seen) return -1; else if (n1->last_seen == n2->last_seen) return 0; else return 1; } static int compare_nodes_channel(const struct list_head *p1, const struct list_head *p2) { struct node_info* n1 = list_entry(p1, struct node_info, list); struct node_info* n2 = list_entry(p2, struct node_info, list); if (n1->wlan_channel < n2->wlan_channel) return 1; else if (n1->wlan_channel == n2->wlan_channel) return 0; else return -1; } static int compare_nodes_bssid(const struct list_head *p1, const struct list_head *p2) { struct node_info* n1 = list_entry(p1, struct node_info, list); struct node_info* n2 = list_entry(p2, struct node_info, list); return -memcmp(n1->wlan_bssid, n2->wlan_bssid, MAC_LEN); } static int sort_input(int c) { switch (c) { case 'n': case 'N': sortfunc = NULL; break; case 's': case 'S': sortfunc = compare_nodes_snr; break; case 't': case 'T': sortfunc = compare_nodes_time; break; case 'c': case 'C': sortfunc = compare_nodes_channel; break; case 'b': case 'B': sortfunc = compare_nodes_bssid; break; } switch (c) { case 'n': case 'N': case 's': case 'S': case 't': case 'T': case 'c': case 'C': case 'b': case 'B': do_sort = c; /* fall thru */ case '\r': case KEY_ENTER: delwin(sort_win); sort_win = NULL; update_display(NULL, NULL); return 1; } return 0; } static void show_sort_win(void) { if (sort_win == NULL) { sort_win = newwin(1, COLS-2, win_split - 2, 1); wattron(sort_win, BLACKONWHITE); mvwhline(sort_win, 0, 0, ' ', COLS); mvwprintw(sort_win, 0, 0, " -> Sort by s:SNR t:Time b:BSSID c:Channel n:Don't sort [current: %c]", do_sort); wrefresh(sort_win); } } /******************* WINDOWS *******************/ #define STAT_WIDTH 11 #define STAT_START 4 static void update_status_win(struct packet_info* p) { int sig, siga, noi = 0, bps, dps, pps, rps, bpsn, usen; float use, rpsp = 0.0; int max_stat_bar = stat_height - STAT_START; struct channel_info* chan = NULL; if (p != NULL) werase(stat_win); wattron(stat_win, WHITE); mvwvline(stat_win, 0, 0, ACS_VLINE, stat_height); get_per_second(stats.bytes, stats.duration, stats.packets, stats.retries, &bps, &dps, &pps, &rps); bps *= 8; bpsn = normalize(bps, 32000000, max_stat_bar); //theoretical: 54000000 use = dps * 1.0 / 10000; /* usec, in percent */ usen = normalize(use, 100, max_stat_bar); if (pps) rpsp = rps * 100.0 / pps; ewma_add(&usen_avg, usen); ewma_add(&bpsn_avg, bpsn); if (p != NULL) { sig = normalize_db(-p->phy_signal, max_stat_bar); if (p->phy_noise) noi = normalize_db(-p->phy_noise, max_stat_bar); if (p->pkt_chan_idx > 0) chan = &spectrum[p->pkt_chan_idx]; if (chan != NULL && chan->packets >= 8) siga = normalize_db(ewma_read(&chan->signal_avg), max_stat_bar); else siga = sig; wattron(stat_win, GREEN); if (conf.have_noise) { mvwprintw(stat_win, 0, 1, "S/ :-%02d/", -p->phy_signal); wattron(stat_win, RED); wprintw(stat_win, "%02d", -p->phy_noise); mvwprintw(stat_win, 0, 3, "N"); } else mvwprintw(stat_win, 0, 1, "Sig: %5d", p->phy_signal); signal_average_bar(stat_win, sig, siga, STAT_START, 2, stat_height, 2); if (noi) { wattron(stat_win, ALLRED); mvwvline(stat_win, noi + STAT_START, 2, '=', stat_height - noi); mvwvline(stat_win, noi + STAT_START, 3, '=', stat_height - noi); } } wattron(stat_win, CYAN); mvwprintw(stat_win, 1, 1, "bps:%6s", kilo_mega_ize(bps)); general_average_bar(stat_win, bpsn, ewma_read(&bpsn_avg), stat_height, 5, max_stat_bar, 2, CYAN, ALLCYAN); wattron(stat_win, YELLOW); mvwprintw(stat_win, 2, 1, "Use:%5.1f%%", use); general_average_bar(stat_win, usen, ewma_read(&usen_avg), stat_height, 8, max_stat_bar, 2, YELLOW, ALLYELLOW); mvwprintw(stat_win, 3, 1, "Retry: %2.0f%%", rpsp); wnoutrefresh(stat_win); } #define COL_PKT 3 #define COL_CHAN COL_PKT + 7 #define COL_SNR COL_CHAN + 3 #define COL_RATE COL_SNR + 3 #define COL_SOURCE COL_RATE + 3 #define COL_STA COL_SOURCE + 18 #define COL_BSSID COL_STA + 2 #define COL_ENC COL_BSSID + 20 #define COL_IP COL_ENC + 2 static char spin[4] = {'/', '-', '\\', '|'}; static void print_list_line(int line, struct node_info* n) { struct packet_info* p = &n->last_pkt; if (n->pkt_types & PKT_TYPE_OLSR) wattron(list_win, GREEN); if (n->last_seen > (the_time.tv_sec - conf.node_timeout / 2)) wattron(list_win, A_BOLD); else wattron(list_win, A_NORMAL); if (n->essid != NULL && n->essid->split > 0) wattron(list_win, RED); mvwprintw(list_win, line, 1, "%c", spin[n->pkt_count % 4]); mvwprintw(list_win, line, COL_PKT, "%.0f/%.0f%%", n->pkt_count * 100.0 / stats.packets, n->wlan_retries_all * 100.0 / n->pkt_count); mvwprintw(list_win, line, COL_SNR, "%2d", ewma_read(&n->phy_snr_avg)); if (n->wlan_mode == WLAN_MODE_AP ) mvwprintw(list_win, line, COL_STA,"A"); else if (n->wlan_mode == WLAN_MODE_IBSS ) mvwprintw(list_win, line, COL_STA, "I"); else if (n->wlan_mode == WLAN_MODE_STA ) mvwprintw(list_win, line, COL_STA, "S"); else if (n->wlan_mode == WLAN_MODE_PROBE ) mvwprintw(list_win, line, COL_STA, "P"); mvwprintw(list_win, line, COL_ENC, n->wlan_wep ? "W" : ""); mvwprintw(list_win, line, COL_RATE, "%2d", p->phy_rate/2); mvwprintw(list_win, line, COL_SOURCE, "%s", ether_sprintf(p->wlan_src)); mvwprintw(list_win, line, COL_BSSID, "(%s)", ether_sprintf(n->wlan_bssid)); if (n->wlan_channel) mvwprintw(list_win, line, COL_CHAN, "%2d", n->wlan_channel ); if (n->pkt_types & PKT_TYPE_IP) mvwprintw(list_win, line, COL_IP, "%s", ip_sprintf(n->ip_src)); if (n->pkt_types & PKT_TYPE_OLSR) wprintw(list_win, " OLSR%s N:%d %s", n->pkt_types & PKT_TYPE_OLSR_LQ ? "_LQ" : "", n->olsr_neigh, n->pkt_types & PKT_TYPE_OLSR_GW ? "GW" : ""); if (n->pkt_types & PKT_TYPE_BATMAN) wprintw(list_win, " BAT"); if (n->pkt_types & (PKT_TYPE_MESHZ)) wprintw(list_win, " MC"); wattroff(list_win, A_BOLD); wattroff(list_win, GREEN); wattroff(list_win, RED); } static void update_list_win(void) { struct node_info* n; int line = 0, nadd = 0; werase(list_win); wattron(list_win, WHITE); box(list_win, 0 , 0); mvwprintw(list_win, 0, COL_PKT, "Pk/Re%%"); mvwprintw(list_win, 0, COL_CHAN, "CH"); mvwprintw(list_win, 0, COL_SNR, "SN"); mvwprintw(list_win, 0, COL_RATE, "RT"); mvwprintw(list_win, 0, COL_SOURCE, "SOURCE"); mvwprintw(list_win, 0, COL_STA, "M"); mvwprintw(list_win, 0, COL_BSSID, "(BSSID)"); mvwprintw(list_win, 0, COL_ENC, "E"); mvwprintw(list_win, 0, COL_IP, "IP/Mesh"); /* reuse bottom line for information on other win */ mvwprintw(list_win, win_split - 1, 0, "CH-Sig"); if (conf.have_noise) { wprintw(list_win, "/No"); nadd = 3; } wprintw(list_win, "-RT-SOURCE"); mvwprintw(list_win, win_split - 1, 28 + nadd, "(BSSID)"); mvwprintw(list_win, win_split - 1, 48 + nadd, "TYPE"); mvwprintw(list_win, win_split - 1, 55 + nadd, "INFO"); mvwprintw(list_win, win_split - 1, COLS-10, "LiveStatus"); if (sortfunc) listsort(&nodes, sortfunc); list_for_each_entry(n, &nodes, list) { line++; if (line >= win_split - 1) break; /* prevent overdraw of last line */ print_list_line(line, n); } if (essids.split_active > 0) { wattron(list_win, WHITEONRED); mvwhline(list_win, win_split - 2, 1, ' ', COLS - 2); print_centered(list_win, win_split - 2, COLS - 2, "*** IBSS SPLIT DETECTED!!! ESSID '%s' %d nodes ***", essids.split_essid->essid, essids.split_essid->num_nodes); wattroff(list_win, WHITEONRED); } wnoutrefresh(list_win); } void update_dump_win(struct packet_info* p) { if (!p) { redrawwin(dump_win); wnoutrefresh(dump_win); return; } wattron(dump_win, get_packet_type_color(p->wlan_type)); if (p->pkt_types & PKT_TYPE_IP) wattron(dump_win, A_BOLD); wprintw(dump_win, "\n%02d ", p->phy_chan); wprintw(dump_win, "-%02d", -p->phy_signal); if (conf.have_noise) wprintw(dump_win, "/%02d ", -p->phy_noise); else wprintw(dump_win, " "); wprintw(dump_win, "%2d ", p->phy_rate/2); wprintw(dump_win, "%s ", ether_sprintf(p->wlan_src)); wprintw(dump_win, "(%s) ", ether_sprintf(p->wlan_bssid)); if (p->wlan_retry) wprintw(dump_win, "[r]"); if (p->pkt_types & PKT_TYPE_OLSR) { wprintw(dump_win, "%-7s%s ", "OLSR", ip_sprintf(p->ip_src)); switch (p->olsr_type) { case HELLO_MESSAGE: wprintw(dump_win, "HELLO"); break; case TC_MESSAGE: wprintw(dump_win, "TC"); break; case MID_MESSAGE: wprintw(dump_win, "MID");break; case HNA_MESSAGE: wprintw(dump_win, "HNA"); break; case LQ_HELLO_MESSAGE: wprintw(dump_win, "LQ_HELLO"); break; case LQ_TC_MESSAGE: wprintw(dump_win, "LQ_TC"); break; default: wprintw(dump_win, "(%d)", p->olsr_type); } } else if (p->pkt_types & PKT_TYPE_BATMAN) { wprintw(dump_win, "%-7s%s", "BAT", ip_sprintf(p->ip_src)); wprintw(dump_win, " -> %s", ip_sprintf(p->ip_dst)); } else if (p->pkt_types & PKT_TYPE_MESHZ) { wprintw(dump_win, "%-7s%s", p->tcpudp_port == 9256 ? "MC_NBR" : "MC_RT", ip_sprintf(p->ip_src)); wprintw(dump_win, " -> %s", ip_sprintf(p->ip_dst)); } else if (p->pkt_types & PKT_TYPE_UDP) { wprintw(dump_win, "%-7s%s", "UDP", ip_sprintf(p->ip_src)); wprintw(dump_win, " -> %s", ip_sprintf(p->ip_dst)); } else if (p->pkt_types & PKT_TYPE_TCP) { wprintw(dump_win, "%-7s%s", "TCP", ip_sprintf(p->ip_src)); wprintw(dump_win, " -> %s", ip_sprintf(p->ip_dst)); } else if (p->pkt_types & PKT_TYPE_ICMP) { wprintw(dump_win, "%-7s%s", "PING", ip_sprintf(p->ip_src)); wprintw(dump_win, " -> %s", ip_sprintf(p->ip_dst)); } else if (p->pkt_types & PKT_TYPE_IP) { wprintw(dump_win, "%-7s%s", "IP", ip_sprintf(p->ip_src)); wprintw(dump_win, " -> %s", ip_sprintf(p->ip_dst)); } else if (p->pkt_types & PKT_TYPE_ARP) { wprintw(dump_win, "%-7s", "ARP", ip_sprintf(p->ip_src)); } else { wprintw(dump_win, "%-7s", get_packet_type_name(p->wlan_type)); switch (p->wlan_type & IEEE80211_FCTL_FTYPE) { case IEEE80211_FTYPE_DATA: if ( p->wlan_wep == 1) wprintw(dump_win, "ENCRYPTED"); break; case IEEE80211_FTYPE_CTL: switch (p->wlan_type & IEEE80211_FCTL_STYPE) { case IEEE80211_STYPE_CTS: case IEEE80211_STYPE_RTS: case IEEE80211_STYPE_ACK: wprintw(dump_win, "%s", ether_sprintf(p->wlan_dst)); break; } break; case IEEE80211_FTYPE_MGMT: switch (p->wlan_type & IEEE80211_FCTL_STYPE) { case IEEE80211_STYPE_BEACON: case IEEE80211_STYPE_PROBE_RESP: wprintw(dump_win, "'%s' %llx", p->wlan_essid, p->wlan_tsf); break; case IEEE80211_STYPE_PROBE_REQ: wprintw(dump_win, "'%s'", p->wlan_essid); break; } } } wattroff(dump_win, A_BOLD); } void update_main_win(struct packet_info *p) { update_list_win(); update_status_win(p); update_dump_win(p); wnoutrefresh(dump_win); if (sort_win != NULL) { redrawwin(sort_win); wnoutrefresh(sort_win); } } int main_input(char key) { if (sort_win != NULL) return sort_input(key); switch(key) { case 'o': case 'O': show_sort_win(); return 1; } return 0; } void init_display_main(void) { win_split = LINES / 2 + 1; stat_height = LINES - win_split - 1; list_win = newwin(win_split, COLS, 0, 0); scrollok(list_win, FALSE); stat_win = newwin(stat_height, STAT_WIDTH, win_split, COLS - STAT_WIDTH); scrollok(stat_win, FALSE); dump_win = newwin(stat_height, COLS - STAT_WIDTH, win_split, 0); scrollok(dump_win, TRUE); ewma_init(&usen_avg, 1024, 8); ewma_init(&bpsn_avg, 1024, 8); } void resize_display_main(void) { win_split = LINES / 2 + 1; stat_height = LINES - win_split - 1; wresize(list_win, win_split, COLS); wresize(dump_win, stat_height, COLS - STAT_WIDTH); mvwin(dump_win, win_split, 0); wresize(stat_win, stat_height, STAT_WIDTH); mvwin(stat_win, win_split, COLS - STAT_WIDTH); } horst-3.0/display-spectrum.c000066400000000000000000000111271152373700300161670ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /******************* POOR MAN's "SPECTRUM ANALYZER" *******************/ #include #include "display.h" #include "main.h" #include "util.h" #define CH_SPACE 6 #define SPEC_POS_Y 1 #define SPEC_HEIGHT (LINES - SPEC_POS_X - 2) #define SPEC_POS_X 6 static unsigned int show_nodes; void update_spectrum_win(WINDOW *win) { int i, sig, noi, siga, use, usen, usean, nnodes; struct chan_node *cn; const char *id; werase(win); wattron(win, WHITE); box(win, 0 , 0); print_centered(win, 0, COLS, " \"Spectrum Analyzer\" "); mvwhline(win, SPEC_HEIGHT + 1, 1, ACS_HLINE, COLS - 2); mvwvline(win, SPEC_POS_Y, 4, ACS_VLINE, LINES - SPEC_POS_Y - 2); mvwprintw(win, SPEC_HEIGHT + 2, 1, "CHA"); wattron(win, BLUE); mvwprintw(win, SPEC_HEIGHT + 4, 1, "Nod"); wattron(win, YELLOW); mvwprintw(win, SPEC_HEIGHT + 5, 1, "Use"); for(i = 80; i > 0; i -= 20) { sig = normalize(i, 100, SPEC_HEIGHT); mvwprintw(win, SPEC_POS_Y + sig, 1, "%d%%", 100-i); } wattron(win, GREEN); mvwprintw(win, SPEC_HEIGHT + 3, 1, "Sig"); mvwprintw(win, SPEC_POS_Y + 1, 1, "dBm"); for(i = -30; i > -100; i -= 10) { sig = normalize_db(-i, SPEC_HEIGHT); mvwprintw(win, SPEC_POS_Y + sig, 1, "%d", i); } wattroff(win, GREEN); for (i = 0; i < conf.num_channels && SPEC_POS_X + CH_SPACE*i+4 < COLS; i++) { mvwprintw(win, SPEC_HEIGHT + 2, SPEC_POS_X + CH_SPACE*i, "%02d", channels[i].chan); wattron(win, GREEN); mvwprintw(win, SPEC_HEIGHT + 3, SPEC_POS_X + CH_SPACE*i, "%d", spectrum[i].signal); wattron(win, BLUE); mvwprintw(win, SPEC_HEIGHT + 4, SPEC_POS_X + CH_SPACE*i, "%d", spectrum[i].num_nodes); if (spectrum[i].signal != 0) { sig = normalize_db(-spectrum[i].signal, SPEC_HEIGHT); if (spectrum[i].packets > 8) siga = normalize_db( ewma_read(&spectrum[i].signal_avg), SPEC_HEIGHT); else siga = sig; signal_average_bar(win, sig, siga, SPEC_POS_Y, SPEC_POS_X + CH_SPACE*i, SPEC_HEIGHT, show_nodes ? 1 : 2); } if (spectrum[i].noise != 0) { noi = normalize_db(-spectrum[i].noise, SPEC_HEIGHT); wattron(win, ALLRED); mvwvline(win, SPEC_POS_Y + noi, SPEC_POS_X + CH_SPACE*i, ACS_BLOCK, SPEC_HEIGHT - noi); } /* usage in percent */ use = (spectrum[i].durations_last * 100.0) / conf.channel_time; wattron(win, YELLOW); mvwprintw(win, SPEC_HEIGHT + 5, SPEC_POS_X + CH_SPACE*i, "%d", use); wattroff(win, YELLOW); if (show_nodes) { wattron(win, BLUE); list_for_each_entry(cn, &spectrum[i].nodes, chan_list) { if (cn->packets >= 8) sig = normalize_db(ewma_read(&cn->sig_avg), SPEC_HEIGHT); else sig = normalize_db(-cn->sig, SPEC_HEIGHT); if (cn->node->ip_src) { wattron(win, A_BOLD); id = ip_sprintf_short(cn->node->ip_src); } else id = ether_sprintf_short(cn->node->last_pkt.wlan_src); mvwprintw(win, SPEC_POS_Y + sig, SPEC_POS_X + CH_SPACE*i + 1, "%s", id); if (cn->node->ip_src) wattroff(win, A_BOLD); } wattroff(win, BLUE); } else { nnodes = spectrum[i].num_nodes; if (nnodes > SPEC_HEIGHT) nnodes = SPEC_HEIGHT; wattron(win, ALLBLUE); mvwvline(win, SPEC_POS_Y + SPEC_HEIGHT - nnodes, SPEC_POS_X + CH_SPACE*i + 2, ACS_BLOCK, nnodes); wattroff(win, ALLBLUE); usen = normalize(use, 100, SPEC_HEIGHT); use = (ewma_read(&spectrum[i].durations_avg) * 100.0) / conf.channel_time; usean = normalize(use, 100, SPEC_HEIGHT); general_average_bar(win, usen, usean, SPEC_POS_Y + SPEC_HEIGHT, SPEC_POS_X + CH_SPACE*i + 3, SPEC_HEIGHT, 1, YELLOW, ALLYELLOW); } } wnoutrefresh(win); } int spectrum_input(WINDOW *win, int c) { switch (c) { case 'n': case 'N': show_nodes = show_nodes ? 0 : 1; break; default: return 0; /* didn't handle input */ } update_spectrum_win(win); return 1; } horst-3.0/display-statistics.c000066400000000000000000000120751152373700300165220ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /******************* STATISTICS *******************/ #include #include "display.h" #include "main.h" #include "util.h" #define STAT_PACK_POS 9 #define STAT_BYTE_POS (STAT_PACK_POS + 9) #define STAT_BPP_POS (STAT_BYTE_POS + 9) #define STAT_PP_POS (STAT_BPP_POS + 6) #define STAT_BP_POS (STAT_PP_POS + 6) #define STAT_AIR_POS (STAT_BP_POS + 6) #define STAT_AIRG_POS (STAT_AIR_POS + 6) void update_statistics_win(WINDOW *win) { int i; int line; int bps, dps, pps, rps; float duration; werase(win); wattron(win, WHITE); box(win, 0 , 0); print_centered(win, 0, COLS, " Packet Statistics "); if (stats.packets == 0) { wnoutrefresh(win); return; /* avoid floating point exceptions */ } mvwprintw(win, 2, 2, "Packets: %d", stats.packets ); mvwprintw(win, 3, 2, "Bytes: %s (%d)", kilo_mega_ize(stats.bytes), stats.bytes ); mvwprintw(win, 4, 2, "Average: ~%d B/Pkt", stats.bytes / stats.packets); mvwprintw(win, 2, 40, "Retries: %3.1f%% (%d)", stats.retries * 100.0 / stats.packets, stats.retries); get_per_second(stats.bytes, stats.duration, stats.packets, stats.retries, &bps, &dps, &pps, &rps); bps = bps * 8; mvwprintw(win, 3, 40, "Total bit/sec: %s (%d)", kilo_mega_ize(bps), bps); wattron(win, A_BOLD); mvwprintw(win, 4, 40, "Total Usage: %3.1f%% (%d)", dps * 1.0 / 10000, dps ); /* usec in % */ wattroff(win, A_BOLD); line = 6; mvwprintw(win, line, STAT_PACK_POS, " Packets"); mvwprintw(win, line, STAT_BYTE_POS, " Bytes"); mvwprintw(win, line, STAT_BPP_POS, "~B/P"); mvwprintw(win, line, STAT_PP_POS, "Pkts%%"); mvwprintw(win, line, STAT_BP_POS, "Byte%%"); wattron(win, A_BOLD); mvwprintw(win, line, STAT_AIR_POS, "Usage%%"); mvwprintw(win, line++, 2, "RATE"); wattroff(win, A_BOLD); mvwhline(win, line++, 2, '-', COLS-4); for (i = 1; i < MAX_RATES && line < LINES - 2; i++) { if (stats.packets_per_rate[i] > 0) { wattron(win, A_BOLD); mvwprintw(win, line, 2, "%3dM", i/2); wattroff(win, A_BOLD); mvwprintw(win, line, STAT_PACK_POS, "%8d", stats.packets_per_rate[i]); mvwprintw(win, line, STAT_BYTE_POS, "%8s", kilo_mega_ize(stats.bytes_per_rate[i])); mvwprintw(win, line, STAT_BPP_POS, "%4d", stats.bytes_per_rate[i] / stats.packets_per_rate[i]); mvwprintw(win, line, STAT_PP_POS, "%2.1f", stats.packets_per_rate[i] * 100.0 / stats.packets); mvwprintw(win, line, STAT_BP_POS, "%2.1f", stats.bytes_per_rate[i] * 100.0 / stats.bytes); wattron(win, A_BOLD); duration = stats.duration_per_rate[i] * 100.0 / stats.duration; mvwprintw(win, line, STAT_AIR_POS, "%2.1f", duration); mvwhline(win, line, STAT_AIRG_POS, '*', normalize(duration, 100, COLS - STAT_AIRG_POS - 2)); wattroff(win, A_BOLD); line++; } } line++; if (line < LINES - 2) { mvwprintw(win, line, STAT_PACK_POS, " Packets"); mvwprintw(win, line, STAT_BYTE_POS, " Bytes"); mvwprintw(win, line, STAT_BPP_POS, "~B/P"); mvwprintw(win, line, STAT_PP_POS, "Pkts%%"); mvwprintw(win, line, STAT_BP_POS, "Byte%%"); wattron(win, A_BOLD); mvwprintw(win, line, STAT_AIR_POS, "Usage%%"); mvwprintw(win, line++, 2, "TYPE"); wattroff(win, A_BOLD); } if (line < LINES - 2) mvwhline(win, line++, 2, '-', COLS - 4); for (i = 0; i < MAX_FSTYPE && line < LINES - 2; i++) { if (stats.packets_per_type[i] > 0) { wattron(win, get_packet_type_color(i)); wattron(win, A_BOLD); mvwprintw(win, line, 2, "%s", get_packet_type_name(i)); wattroff(win, A_BOLD); mvwprintw(win, line, STAT_PACK_POS, "%8d", stats.packets_per_type[i]); mvwprintw(win, line, STAT_BYTE_POS, "%8s", kilo_mega_ize(stats.bytes_per_type[i])); mvwprintw(win, line, STAT_BPP_POS, "%4d", stats.bytes_per_type[i] / stats.packets_per_type[i]); mvwprintw(win, line, STAT_PP_POS, "%2.1f", stats.packets_per_type[i] * 100.0 / stats.packets); mvwprintw(win, line, STAT_BP_POS, "%2.1f", stats.bytes_per_type[i] * 100.0 / stats.bytes); wattron(win, A_BOLD); if (stats.duration > 0) duration = stats.duration_per_type[i] * 100.0 / stats.duration; else duration = 100.0; mvwprintw(win, line, STAT_AIR_POS, "%2.1f", duration); mvwhline(win, line, STAT_AIRG_POS, '*', normalize(duration, 100, COLS - STAT_AIRG_POS - 2)); wattroff(win, A_BOLD); line++; } } wnoutrefresh(win); } horst-3.0/display.c000066400000000000000000000302711152373700300143300ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include "display.h" #include "main.h" #include "ieee80211.h" WINDOW *conf_win = NULL; WINDOW *show_win = NULL; static int conf_win_current; static int show_win_current; static struct timeval last_time; /* main windows are special */ void init_display_main(void); void update_main_win(struct packet_info *pkt); void update_dump_win(struct packet_info* pkt); int main_input(int c); void print_dump_win(const char *str, int refresh); void resize_display_main(void); /* smaller config windows */ void update_filter_win(WINDOW *win); void update_channel_win(WINDOW *win); int filter_input(WINDOW *win, int c); int channel_input(WINDOW *win, int c); /* "standard" windows */ void update_spectrum_win(WINDOW *win); void update_statistics_win(WINDOW *win); void update_essid_win(WINDOW *win); void update_history_win(WINDOW *win); void update_help_win(WINDOW *win); int spectrum_input(WINDOW *win, int c); /******************* HELPERS *******************/ void get_per_second(unsigned int bytes, unsigned int duration, unsigned int packets, unsigned int retries, int *bps, int *dps, int *pps, int *rps) { static struct timeval last; static unsigned long last_bytes, last_dur, last_pkts, last_retr; static int last_bps, last_dps, last_pps, last_rps; float timediff; /* reacalculate only every second or more */ timediff = (the_time.tv_sec + the_time.tv_usec/1000000.0) - (last.tv_sec + last.tv_usec/1000000.0); if (timediff >= 1.0) { last_dps = (1.0*(duration - last_dur)) / timediff; last_bps = (1.0*(bytes - last_bytes)) / timediff; last_pps = (1.0*(packets - last_pkts)) / timediff; last_rps = (1.0*(retries - last_retr)) / timediff; last = the_time; last_dur = duration; last_bytes = bytes; last_pkts = packets; last_retr = retries; } *bps = last_bps; *dps = last_dps; *pps = last_pps; *rps = last_rps; } void __attribute__ ((format (printf, 4, 5))) print_centered(WINDOW* win, int line, int cols, const char *fmt, ...) { char* buf; va_list ap; buf = malloc(cols); if (buf == NULL) return; va_start(ap, fmt); vsnprintf(buf, cols, fmt, ap); va_end(ap); mvwprintw(win, line, cols / 2 - strlen(buf) / 2, buf); free(buf); } int get_packet_type_color(int type) { switch (type & IEEE80211_FCTL_FTYPE) { case IEEE80211_FTYPE_DATA: return BLUE; case IEEE80211_FTYPE_CTL: return WHITE; case IEEE80211_FTYPE_MGMT: return CYAN; } return YELLOW; } void signal_average_bar(WINDOW *win, int val, int avg, int y, int x, int height, int width) { int i; if (avg <= val) { wattron(win, ALLGREEN); for (i = 0; i < width; i++) mvwvline(win, y + avg, x + i, ACS_BLOCK, val - avg); wattron(win, A_BOLD); for (i = 0; i < width; i++) mvwvline(win, y + val, x + i, '=', height - val); } else { wattron(win, GREEN); wattron(win, A_BOLD); for (i = 0; i < width; i++) mvwvline(win, y + val, x + i, '=', avg - val); wattron(win, ALLGREEN); for (i = 0; i < width; i++) mvwvline(win, y + avg, x + i, '=', height - avg); } wattroff(win, A_BOLD); wattroff(win, ALLGREEN); } void general_average_bar(WINDOW *win, int val, int avg, int y, int x, int height, int width, short color, short color_avg) { int i; if (avg >= val) { wattron(win, color_avg); for (i = 0; i < width; i++) mvwvline(win, y - avg, x + i, ACS_BLOCK, avg - val); wattron(win, A_BOLD); for (i = 0; i < width; i++) mvwvline(win, y - val, x + i, '=', val); } else { wattron(win, color); wattron(win, A_BOLD); for (i = 0; i < width; i++) mvwvline(win, y - val, x + i, '=', val - avg); wattron(win, color_avg); for (i = 0; i < width; i++) mvwvline(win, y - avg, x + i, '=', avg); } wattroff(win, A_BOLD); wattroff(win, color_avg); } /******************* STATUS *******************/ static void update_clock(time_t* sec) { static char buf[9]; strftime(buf, 9, "%H:%M:%S", localtime(sec)); wattron(stdscr, BLACKONWHITE); mvwprintw(stdscr, LINES-1, COLS-9, "|%s", buf); wattroff(stdscr, BLACKONWHITE); wnoutrefresh(stdscr); } static void update_mini_status(void) { wattron(stdscr, BLACKONWHITE); mvwprintw(stdscr, LINES-1, COLS-24, conf.paused ? "|=" : "|>"); if (!conf.filter_off && (conf.do_macfilter || conf.filter_pkt != 0xffffff)) mvwprintw(stdscr, LINES-1, COLS-22, "|F"); else mvwprintw(stdscr, LINES-1, COLS-22, "| "); mvwprintw(stdscr, LINES-1, COLS-20, "|Ch%02d", CONF_CURRENT_CHANNEL); wattroff(stdscr, BLACKONWHITE); wnoutrefresh(stdscr); } static void update_menu(void) { wattron(stdscr, BLACKONWHITE); mvwhline(stdscr, LINES-1, 0, ' ', COLS); #define KEYMARK A_UNDERLINE attron(KEYMARK); printw("Q"); attroff(KEYMARK); printw("uit "); attron(KEYMARK); printw("P"); attroff(KEYMARK); printw("ause "); attron(KEYMARK); printw("R"); attroff(KEYMARK); printw("eset "); attron(KEYMARK); printw("H"); attroff(KEYMARK); printw("ist "); attron(KEYMARK); printw("E"); attroff(KEYMARK); printw("SSID St"); attron(KEYMARK); printw("a"); attroff(KEYMARK); printw("ts "); attron(KEYMARK); printw("S"); attroff(KEYMARK); printw("pec "); attron(KEYMARK); printw("F"); attroff(KEYMARK); printw("ilt "); attron(KEYMARK); printw("C"); attroff(KEYMARK); printw("han "); attron(KEYMARK); printw("?"); attroff(KEYMARK); printw(" "); if (show_win == NULL) { printw("s"); attron(KEYMARK); printw("O"); attroff(KEYMARK); printw("rt"); } if (show_win != NULL && show_win_current == 's') { attron(KEYMARK); printw("N"); attroff(KEYMARK); printw("odes"); } #undef KEYMARK mvwprintw(stdscr, LINES-1, COLS-15, "|%s", conf.serveraddr ? conf.serveraddr : conf.ifname); wattroff(stdscr, BLACKONWHITE); update_mini_status(); update_clock(&the_time.tv_sec); } /******************* WINDOW MANAGEMENT / UPDATE *******************/ static void update_show_win(void) { if (show_win_current == 'e') update_essid_win(show_win); else if (show_win_current == 'h') update_history_win(show_win); else if (show_win_current == 'a') update_statistics_win(show_win); else if (show_win_current == 's') update_spectrum_win(show_win); else if (show_win_current == '?') update_help_win(show_win); } static void show_window(int which) { if (show_win != NULL && show_win_current == which) { delwin(show_win); show_win = NULL; show_win_current = 0; update_menu(); return; } if (show_win == NULL) { show_win = newwin(LINES-1, COLS, 0, 0); scrollok(show_win, FALSE); } show_win_current = which; update_show_win(); update_menu(); } static void show_conf_window(int key) { if (conf_win != NULL && (conf_win_current == key || key == '\r' || key == KEY_ENTER)) { delwin(conf_win); conf_win = NULL; conf_win_current = 0; return; } if (conf_win == NULL) { if (key == 'f') { conf_win = newwin(26, 57, LINES/2-13, COLS/2-28); update_filter_win(conf_win); } else if (key == 'c') { conf_win = newwin(10, 39, LINES/2-5, COLS/2-20); update_channel_win(conf_win); } scrollok(conf_win, FALSE); conf_win_current = key; } } void update_display_clock(void) { /* helper to update just the clock every second */ if (the_time.tv_sec > last_time.tv_sec) { update_clock(&the_time.tv_sec); doupdate(); } } void display_log(const char *string) { print_dump_win(string, show_win == NULL); } void update_display(struct packet_info* pkt, struct node_info* node) { /* * update only in specific intervals to save CPU time * if pkt is NULL we want to force an update */ if (pkt != NULL && the_time.tv_sec == last_time.tv_sec && (the_time.tv_usec - last_time.tv_usec) < conf.display_interval ) { /* just add the line to dump win so we don't loose it */ update_dump_win(pkt); return; } update_menu(); /* update clock every second */ if (the_time.tv_sec > last_time.tv_sec) update_clock(&the_time.tv_sec); last_time = the_time; if (show_win != NULL) update_show_win(); else update_main_win(pkt); if (conf_win != NULL) { redrawwin(conf_win); wnoutrefresh(conf_win); } /* only one redraw */ doupdate(); } /******************* RESIZE *******************/ void resize_display_all() { resize_display_main(); if (show_win) wresize(show_win, LINES-1, COLS); if (conf_win) { if (conf_win_current == 'f') mvwin(conf_win, LINES/2-12, COLS/2-28); else if (conf_win_current == 'c') mvwin(conf_win, LINES/2-5, COLS/2-20); } update_menu(); update_display(NULL, NULL); } void window_change_handler(int sig) { struct winsize winsz; winsz.ws_col = winsz.ws_row = 0; ioctl(0, TIOCGWINSZ, &winsz); /* ioctl on STDIN */ if (winsz.ws_col && winsz.ws_row) resizeterm(winsz.ws_row, winsz.ws_col); COLS = winsz.ws_col; LINES = winsz.ws_row; resize_display_all(); } /******************* INPUT *******************/ void handle_user_input(void) { int key; key = getch(); /* if windows are active pass the input to them first. if they handle * it they will return 1. if not we handle the input below */ if (conf_win != NULL) { if (conf_win_current == 'f') if (filter_input(conf_win, key)) return; if (conf_win_current == 'c') if (channel_input(conf_win, key)) return; } if (show_win != NULL && show_win_current == 's') if (spectrum_input(show_win, key)) return; if (show_win == NULL) { if (main_input(key)) return; } switch(key) { case ' ': case 'p': case 'P': conf.paused = conf.paused ? 0 : 1; print_dump_win(conf.paused ? "\n- PAUSED -" : "\n- RESUME -", show_win == NULL); break; case 'q': case 'Q': exit(0); case 'r': case 'R': print_dump_win("\n- RESET -", show_win == NULL); free_lists(); essids.split_active = 0; essids.split_essid = NULL; memset(&hist, 0, sizeof(hist)); memset(&stats, 0, sizeof(stats)); memset(&spectrum, 0, sizeof(spectrum)); init_channels(); gettimeofday(&stats.stats_time, NULL); break; /* big windows */ case '?': case 'e': case 'E': case 'h': case 'H': case 'a': case 'A': case 's': case 'S': show_window(tolower(key)); break; /* config windows */ case 'f': case 'F': case 'c': case 'C': case '\r': case KEY_ENTER: /* used to close win */ show_conf_window(tolower(key)); break; } update_display(NULL, NULL); } /******************* INIT *******************/ void init_display(void) { initscr(); start_color(); /* Start the color functionality */ keypad(stdscr, TRUE); nonl(); /* tell curses not to do NL->CR/NL on output */ cbreak(); /* take input chars one at a time, no wait for \n */ curs_set(0); /* don't show cursor */ noecho(); nodelay(stdscr, TRUE); init_pair(1, COLOR_WHITE, COLOR_BLACK); init_pair(2, COLOR_GREEN, COLOR_BLACK); init_pair(3, COLOR_RED, COLOR_BLACK); init_pair(4, COLOR_CYAN, COLOR_BLACK); init_pair(5, COLOR_BLUE, COLOR_BLACK); init_pair(6, COLOR_BLACK, COLOR_WHITE); init_pair(7, COLOR_MAGENTA, COLOR_BLACK); init_pair(8, COLOR_GREEN, COLOR_GREEN); init_pair(9, COLOR_RED, COLOR_RED); init_pair(10, COLOR_BLUE, COLOR_BLUE); init_pair(11, COLOR_CYAN, COLOR_CYAN); init_pair(12, COLOR_YELLOW, COLOR_BLACK); init_pair(13, COLOR_YELLOW, COLOR_YELLOW); init_pair(14, COLOR_WHITE, COLOR_RED); /* COLOR_BLACK COLOR_RED COLOR_GREEN COLOR_YELLOW COLOR_BLUE COLOR_MAGENTA COLOR_CYAN COLOR_WHITE */ erase(); init_display_main(); if (conf.do_change_channel) show_window('s'); update_menu(); update_display(NULL, NULL); signal(SIGWINCH, window_change_handler); conf.display_initialized = 1; } void finish_display(void) { endwin(); } horst-3.0/display.h000066400000000000000000000041541152373700300143360ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _DISPLAY_H_ #define _DISPLAY_H_ #include #define WHITE COLOR_PAIR(1) #define GREEN COLOR_PAIR(2) #define RED COLOR_PAIR(3) #define CYAN COLOR_PAIR(4) #define BLUE COLOR_PAIR(5) #define BLACKONWHITE COLOR_PAIR(6) #define MAGENTA COLOR_PAIR(7) #define ALLGREEN COLOR_PAIR(8) #define ALLRED COLOR_PAIR(9) #define ALLBLUE COLOR_PAIR(10) #define ALLCYAN COLOR_PAIR(11) #define YELLOW COLOR_PAIR(12) #define ALLYELLOW COLOR_PAIR(13) #define WHITEONRED COLOR_PAIR(14) struct packet_info; struct node_info; void get_per_second(unsigned int bytes, unsigned int duration, unsigned int packets, unsigned int retries, int *bps, int *dps, int *pps, int *rps); void __attribute__ ((format (printf, 4, 5))) print_centered(WINDOW* win, int line, int cols, const char *fmt, ...); int get_packet_type_color(int type); void signal_average_bar(WINDOW *win, int sig, int siga, int y, int x, int height, int width); void general_average_bar(WINDOW *win, int val, int avg, int y, int x, int height, int width, short color, short color_avg); void update_display(struct packet_info* pkg, struct node_info* node); void update_display_clock(void); void display_log(const char *string); void handle_user_input(void); void init_display(void); void finish_display(void); #endif horst-3.0/essid.c000066400000000000000000000070351152373700300137740ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include "main.h" #include "util.h" #include "ieee80211.h" static void update_essid_split_status(struct essid_info* e) { struct node_info* n; unsigned char* last_bssid = NULL; e->split = 0; /* essid can't be split if it only contains 1 node */ if (e->num_nodes <= 1 && essids.split_essid == e) { essids.split_active = 0; essids.split_essid = NULL; return; } /* check for split */ list_for_each_entry(n, &e->nodes, essid_nodes) { DEBUG("SPLIT node %p src %s", n, ether_sprintf(n->last_pkt.wlan_src)); DEBUG(" bssid %s\n", ether_sprintf(n->wlan_bssid)); if (n->wlan_mode == WLAN_MODE_AP) continue; if (last_bssid && memcmp(last_bssid, n->wlan_bssid, MAC_LEN) != 0) { e->split = 1; DEBUG("SPLIT *** DETECTED!!!\n"); } last_bssid = n->wlan_bssid; } /* if a split occurred on this essid, record it */ if (e->split > 0) { DEBUG("SPLIT *** active\n"); essids.split_active = 1; essids.split_essid = e; } else if (e == essids.split_essid) { DEBUG("SPLIT *** ok now\n"); essids.split_active = 0; essids.split_essid = NULL; } } void remove_node_from_essid(struct node_info* n) { DEBUG("SPLIT remove node from old essid\n"); list_del(&n->essid_nodes); n->essid->num_nodes--; update_essid_split_status(n->essid); /* delete essid if it has no more nodes */ if (n->essid->num_nodes == 0) { DEBUG("SPLIT essid empty, delete\n"); list_del(&n->essid->list); free(n->essid); } n->essid = NULL; } void update_essids(struct packet_info* p, struct node_info* n) { struct essid_info* e; /* only check beacons (XXX: what about PROBE?) */ if (!IEEE80211_IS_MGMT_STYPE(p->wlan_type, IEEE80211_STYPE_BEACON)) return; if (n == NULL) return; DEBUG("SPLIT check ibss '%s' node %s ", p->wlan_essid, ether_sprintf(p->wlan_src)); DEBUG("bssid %s\n", ether_sprintf(p->wlan_bssid)); /* find essid if already recorded */ list_for_each_entry(e, &essids.list, list) { if (strncmp(e->essid, p->wlan_essid, MAX_ESSID_LEN) == 0) { DEBUG("SPLIT essid found\n"); break; } } /* if not add new essid */ if (&e->list == &essids.list) { DEBUG("SPLIT essid not found, adding new\n"); e = malloc(sizeof(struct essid_info)); strncpy(e->essid, p->wlan_essid, MAX_ESSID_LEN); e->num_nodes = 0; e->split = 0; INIT_LIST_HEAD(&e->nodes); list_add_tail(&e->list, &essids.list); } /* if node had another essid before, remove it there */ if (n->essid != NULL && n->essid != e) remove_node_from_essid(n); /* new node */ if (n->essid == NULL) { DEBUG("SPLIT node not found, adding new %s\n", ether_sprintf(p->wlan_src)); list_add_tail(&n->essid_nodes, &e->nodes); e->num_nodes++; n->essid = e; } update_essid_split_status(e); } horst-3.0/horst.sh000077500000000000000000000005161152373700300142140ustar00rootroot00000000000000#!/bin/sh if grep -q ath[0-9]: /proc/net/dev;then BASE=wifi0 if [ -n "$1" ] && [ -z "${1#wifi[0-9]}" ];then BASE=$1 shift fi WLDEV=mon0 wlanconfig $WLDEV create wlandev $BASE wlanmode monitor >/dev/null ip link set dev $WLDEV up horst -i $WLDEV $* ip link set dev $WLDEV down wlanconfig $WLDEV destroy else horst $* fi horst-3.0/ieee80211.h000066400000000000000000000300341152373700300141700ustar00rootroot00000000000000/* copied from linux wireless-2.6/linux/ieee80211.h */ /* * IEEE 802.11 defines * * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen * * Copyright (c) 2002-2003, Jouni Malinen * Copyright (c) 2005, Devicescape Software, Inc. * Copyright (c) 2006, Michael Wu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #ifndef IEEE80211_H #define IEEE80211_H #include typedef u_int8_t u8; typedef u_int16_t u16; typedef u_int16_t __le16; typedef u_int64_t __le64; #define le16_to_cpu(_x) (_x) #define FCS_LEN 4 #define IEEE80211_FCTL_VERS 0x0003 #define IEEE80211_FCTL_FTYPE 0x000c #define IEEE80211_FCTL_STYPE 0x00f0 #define IEEE80211_FCTL_TODS 0x0100 #define IEEE80211_FCTL_FROMDS 0x0200 #define IEEE80211_FCTL_MOREFRAGS 0x0400 #define IEEE80211_FCTL_RETRY 0x0800 #define IEEE80211_FCTL_PM 0x1000 #define IEEE80211_FCTL_MOREDATA 0x2000 #define IEEE80211_FCTL_PROTECTED 0x4000 #define IEEE80211_FCTL_ORDER 0x8000 #define IEEE80211_SCTL_FRAG 0x000F #define IEEE80211_SCTL_SEQ 0xFFF0 #define IEEE80211_FTYPE_MGMT 0x0000 #define IEEE80211_FTYPE_CTL 0x0004 #define IEEE80211_FTYPE_DATA 0x0008 /* management */ #define IEEE80211_STYPE_ASSOC_REQ 0x0000 #define IEEE80211_STYPE_ASSOC_RESP 0x0010 #define IEEE80211_STYPE_REASSOC_REQ 0x0020 #define IEEE80211_STYPE_REASSOC_RESP 0x0030 #define IEEE80211_STYPE_PROBE_REQ 0x0040 #define IEEE80211_STYPE_PROBE_RESP 0x0050 #define IEEE80211_STYPE_BEACON 0x0080 #define IEEE80211_STYPE_ATIM 0x0090 #define IEEE80211_STYPE_DISASSOC 0x00A0 #define IEEE80211_STYPE_AUTH 0x00B0 #define IEEE80211_STYPE_DEAUTH 0x00C0 #define IEEE80211_STYPE_ACTION 0x00D0 /* control */ #define IEEE80211_STYPE_PSPOLL 0x00A0 #define IEEE80211_STYPE_RTS 0x00B0 #define IEEE80211_STYPE_CTS 0x00C0 #define IEEE80211_STYPE_ACK 0x00D0 #define IEEE80211_STYPE_CFEND 0x00E0 #define IEEE80211_STYPE_CFENDACK 0x00F0 /* data */ #define IEEE80211_STYPE_DATA 0x0000 #define IEEE80211_STYPE_DATA_CFACK 0x0010 #define IEEE80211_STYPE_DATA_CFPOLL 0x0020 #define IEEE80211_STYPE_DATA_CFACKPOLL 0x0030 #define IEEE80211_STYPE_NULLFUNC 0x0040 #define IEEE80211_STYPE_CFACK 0x0050 #define IEEE80211_STYPE_CFPOLL 0x0060 #define IEEE80211_STYPE_CFACKPOLL 0x0070 #define IEEE80211_STYPE_QOS_DATA 0x0080 #define IEEE80211_STYPE_QOS_DATA_CFACK 0x0090 #define IEEE80211_STYPE_QOS_DATA_CFPOLL 0x00A0 #define IEEE80211_STYPE_QOS_DATA_CFACKPOLL 0x00B0 #define IEEE80211_STYPE_QOS_NULLFUNC 0x00C0 #define IEEE80211_STYPE_QOS_CFACK 0x00D0 #define IEEE80211_STYPE_QOS_CFPOLL 0x00E0 #define IEEE80211_STYPE_QOS_CFACKPOLL 0x00F0 /* miscellaneous IEEE 802.11 constants */ #define IEEE80211_MAX_FRAG_THRESHOLD 2346 #define IEEE80211_MAX_RTS_THRESHOLD 2347 #define IEEE80211_MAX_AID 2007 #define IEEE80211_MAX_TIM_LEN 251 #define IEEE80211_MAX_DATA_LEN 2304 /* Maximum size for the MA-UNITDATA primitive, 802.11 standard section 6.2.1.1.2. The figure in section 7.1.2 suggests a body size of up to 2312 bytes is allowed, which is a bit confusing, I suspect this represents the 2304 bytes of real data, plus a possible 8 bytes of WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ #define IEEE80211_MAX_SSID_LEN 32 struct ieee80211_hdr { __le16 frame_control; __le16 duration_id; u8 addr1[6]; u8 addr2[6]; u8 addr3[6]; __le16 seq_ctrl; u8 addr4[6]; } __attribute__ ((packed)); struct ieee80211_mgmt { __le16 frame_control; __le16 duration; u8 da[6]; u8 sa[6]; u8 bssid[6]; __le16 seq_ctrl; union { struct { __le16 auth_alg; __le16 auth_transaction; __le16 status_code; /* possibly followed by Challenge text */ u8 variable[0]; } __attribute__ ((packed)) auth; struct { __le16 reason_code; } __attribute__ ((packed)) deauth; struct { __le16 capab_info; __le16 listen_interval; /* followed by SSID and Supported rates */ u8 variable[0]; } __attribute__ ((packed)) assoc_req; struct { __le16 capab_info; __le16 status_code; __le16 aid; /* followed by Supported rates */ u8 variable[0]; } __attribute__ ((packed)) assoc_resp, reassoc_resp; struct { __le16 capab_info; __le16 listen_interval; u8 current_ap[6]; /* followed by SSID and Supported rates */ u8 variable[0]; } __attribute__ ((packed)) reassoc_req; struct { __le16 reason_code; } __attribute__ ((packed)) disassoc; struct { __le64 timestamp; __le16 beacon_int; __le16 capab_info; /* followed by some of SSID, Supported rates, * FH Params, DS Params, CF Params, IBSS Params, TIM */ u8 variable[0]; } __attribute__ ((packed)) beacon; struct { /* only variable items: SSID, Supported rates */ u8 variable[0]; } __attribute__ ((packed)) probe_req; struct { __le64 timestamp; __le16 beacon_int; __le16 capab_info; /* followed by some of SSID, Supported rates, * FH Params, DS Params, CF Params, IBSS Params */ u8 variable[0]; } __attribute__ ((packed)) probe_resp; struct { u8 category; union { struct { u8 action_code; u8 dialog_token; u8 status_code; u8 variable[0]; } __attribute__ ((packed)) wme_action; struct{ u8 action_code; u8 element_id; u8 length; u8 switch_mode; u8 new_chan; u8 switch_count; } __attribute__((packed)) chan_switch; } u; } __attribute__ ((packed)) action; } u; } __attribute__ ((packed)); /* Control frames */ struct ieee80211_rts { __le16 frame_control; __le16 duration; u8 ra[6]; u8 ta[6]; } __attribute__ ((packed)); struct ieee80211_cts { __le16 frame_control; __le16 duration; u8 ra[6]; } __attribute__ ((packed)); /* Authentication algorithms */ #define WLAN_AUTH_OPEN 0 #define WLAN_AUTH_SHARED_KEY 1 #define WLAN_AUTH_FAST_BSS_TRANSITION 2 #define WLAN_AUTH_LEAP 128 #define WLAN_AUTH_CHALLENGE_LEN 128 #define WLAN_CAPABILITY_ESS (1<<0) #define WLAN_CAPABILITY_IBSS (1<<1) #define WLAN_CAPABILITY_CF_POLLABLE (1<<2) #define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3) #define WLAN_CAPABILITY_PRIVACY (1<<4) #define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5) #define WLAN_CAPABILITY_PBCC (1<<6) #define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7) /* 802.11h */ #define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8) #define WLAN_CAPABILITY_QOS (1<<9) #define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10) #define WLAN_CAPABILITY_DSSS_OFDM (1<<13) /* 802.11g ERP information element */ #define WLAN_ERP_NON_ERP_PRESENT (1<<0) #define WLAN_ERP_USE_PROTECTION (1<<1) #define WLAN_ERP_BARKER_PREAMBLE (1<<2) /* WLAN_ERP_BARKER_PREAMBLE values */ enum { WLAN_ERP_PREAMBLE_SHORT = 0, WLAN_ERP_PREAMBLE_LONG = 1, }; /* Status codes */ enum ieee80211_statuscode { WLAN_STATUS_SUCCESS = 0, WLAN_STATUS_UNSPECIFIED_FAILURE = 1, WLAN_STATUS_CAPS_UNSUPPORTED = 10, WLAN_STATUS_REASSOC_NO_ASSOC = 11, WLAN_STATUS_ASSOC_DENIED_UNSPEC = 12, WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG = 13, WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION = 14, WLAN_STATUS_CHALLENGE_FAIL = 15, WLAN_STATUS_AUTH_TIMEOUT = 16, WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17, WLAN_STATUS_ASSOC_DENIED_RATES = 18, /* 802.11b */ WLAN_STATUS_ASSOC_DENIED_NOSHORTPREAMBLE = 19, WLAN_STATUS_ASSOC_DENIED_NOPBCC = 20, WLAN_STATUS_ASSOC_DENIED_NOAGILITY = 21, /* 802.11h */ WLAN_STATUS_ASSOC_DENIED_NOSPECTRUM = 22, WLAN_STATUS_ASSOC_REJECTED_BAD_POWER = 23, WLAN_STATUS_ASSOC_REJECTED_BAD_SUPP_CHAN = 24, /* 802.11g */ WLAN_STATUS_ASSOC_DENIED_NOSHORTTIME = 25, WLAN_STATUS_ASSOC_DENIED_NODSSSOFDM = 26, /* 802.11i */ WLAN_STATUS_INVALID_IE = 40, WLAN_STATUS_INVALID_GROUP_CIPHER = 41, WLAN_STATUS_INVALID_PAIRWISE_CIPHER = 42, WLAN_STATUS_INVALID_AKMP = 43, WLAN_STATUS_UNSUPP_RSN_VERSION = 44, WLAN_STATUS_INVALID_RSN_IE_CAP = 45, WLAN_STATUS_CIPHER_SUITE_REJECTED = 46, }; /* Reason codes */ enum ieee80211_reasoncode { WLAN_REASON_UNSPECIFIED = 1, WLAN_REASON_PREV_AUTH_NOT_VALID = 2, WLAN_REASON_DEAUTH_LEAVING = 3, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY = 4, WLAN_REASON_DISASSOC_AP_BUSY = 5, WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA = 6, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA = 7, WLAN_REASON_DISASSOC_STA_HAS_LEFT = 8, WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH = 9, /* 802.11h */ WLAN_REASON_DISASSOC_BAD_POWER = 10, WLAN_REASON_DISASSOC_BAD_SUPP_CHAN = 11, /* 802.11i */ WLAN_REASON_INVALID_IE = 13, WLAN_REASON_MIC_FAILURE = 14, WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT = 15, WLAN_REASON_GROUP_KEY_HANDSHAKE_TIMEOUT = 16, WLAN_REASON_IE_DIFFERENT = 17, WLAN_REASON_INVALID_GROUP_CIPHER = 18, WLAN_REASON_INVALID_PAIRWISE_CIPHER = 19, WLAN_REASON_INVALID_AKMP = 20, WLAN_REASON_UNSUPP_RSN_VERSION = 21, WLAN_REASON_INVALID_RSN_IE_CAP = 22, WLAN_REASON_IEEE8021X_FAILED = 23, WLAN_REASON_CIPHER_SUITE_REJECTED = 24, }; /* Information Element IDs */ enum ieee80211_eid { WLAN_EID_SSID = 0, WLAN_EID_SUPP_RATES = 1, WLAN_EID_FH_PARAMS = 2, WLAN_EID_DS_PARAMS = 3, WLAN_EID_CF_PARAMS = 4, WLAN_EID_TIM = 5, WLAN_EID_IBSS_PARAMS = 6, WLAN_EID_CHALLENGE = 16, /* 802.11d */ WLAN_EID_COUNTRY = 7, WLAN_EID_HP_PARAMS = 8, WLAN_EID_HP_TABLE = 9, WLAN_EID_REQUEST = 10, /* 802.11h */ WLAN_EID_PWR_CONSTRAINT = 32, WLAN_EID_PWR_CAPABILITY = 33, WLAN_EID_TPC_REQUEST = 34, WLAN_EID_TPC_REPORT = 35, WLAN_EID_SUPPORTED_CHANNELS = 36, WLAN_EID_CHANNEL_SWITCH = 37, WLAN_EID_MEASURE_REQUEST = 38, WLAN_EID_MEASURE_REPORT = 39, WLAN_EID_QUIET = 40, WLAN_EID_IBSS_DFS = 41, /* 802.11g */ WLAN_EID_ERP_INFO = 42, WLAN_EID_EXT_SUPP_RATES = 50, /* 802.11i */ WLAN_EID_RSN = 48, WLAN_EID_WPA = 221, WLAN_EID_GENERIC = 221, WLAN_EID_VENDOR_SPECIFIC = 221, WLAN_EID_QOS_PARAMETER = 222 }; /* cipher suite selectors */ #define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00 #define WLAN_CIPHER_SUITE_WEP40 0x000FAC01 #define WLAN_CIPHER_SUITE_TKIP 0x000FAC02 /* reserved: 0x000FAC03 */ #define WLAN_CIPHER_SUITE_CCMP 0x000FAC04 #define WLAN_CIPHER_SUITE_WEP104 0x000FAC05 #define WLAN_MAX_KEY_LEN 32 /** * ieee80211_get_SA - get pointer to SA * * Given an 802.11 frame, this function returns the offset * to the source address (SA). It does not verify that the * header is long enough to contain the address, and the * header must be long enough to contain the frame control * field. * * @hdr: the frame */ static inline u8 *ieee80211_get_SA(struct ieee80211_hdr *hdr) { u8 *raw = (u8 *) hdr; u8 tofrom = (*(raw+1)) & 3; /* get the TODS and FROMDS bits */ switch (tofrom) { case 2: return hdr->addr3; case 3: return hdr->addr4; } return hdr->addr2; } /** * ieee80211_get_DA - get pointer to DA * * Given an 802.11 frame, this function returns the offset * to the destination address (DA). It does not verify that * the header is long enough to contain the address, and the * header must be long enough to contain the frame control * field. * * @hdr: the frame */ static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr) { u8 *raw = (u8 *) hdr; u8 to_ds = (*(raw+1)) & 1; /* get the TODS bit */ if (to_ds) return hdr->addr3; return hdr->addr1; } /** * ieee80211_get_morefrag - determine whether the MOREFRAGS bit is set * * This function determines whether the "more fragments" bit is set * in the frame. * * @hdr: the frame */ static inline int ieee80211_get_morefrag(struct ieee80211_hdr *hdr) { return (le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_MOREFRAGS) != 0; } #define IEEE80211_IS_MGMT(_fc) \ ((_fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) #define IEEE80211_IS_CTRL(_fc) \ ((_fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) #define IEEE80211_IS_DATA(_fc) \ ((_fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) #define IEEE80211_IS_MGMT_STYPE(_fc, _x) \ (((_fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && \ ((_fc & IEEE80211_FCTL_STYPE) == _x)) #define IEEE80211_IS_CTRL_STYPE(_fc, _x) \ (((_fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && \ ((_fc & IEEE80211_FCTL_STYPE) == _x)) #define IEEE80211_IS_DATA_STYPE(_fc, _x) \ (((_fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && \ ((_fc & IEEE80211_FCTL_STYPE) == _x)) #endif /* IEEE80211_H */ horst-3.0/ieee80211_radiotap.h000066400000000000000000000237341152373700300160640ustar00rootroot00000000000000/* copied from madwifi net80211/ieee80211_radiotap.h */ /* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */ /* $NetBSD: ieee80211_radiotap.h,v 1.17 2007/03/26 04:32:14 dyoung Exp $ */ /*- * Copyright (c) 2003, 2004 David Young. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. The name of David Young may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``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 DAVID * YOUNG 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. * * $Id: ieee80211_radiotap.h 2220 2007-03-26 11:56:18Z scottr $ */ #ifndef _NET_IF_IEEE80211RADIOTAP_H_ #define _NET_IF_IEEE80211RADIOTAP_H_ /* A generic radio capture format is desirable. There is one for * Linux, but it is neither rigidly defined (there were not even * units given for some fields) nor easily extensible. * * I suggest the following extensible radio capture format. It is * based on a bitmap indicating which fields are present. * * I am trying to descrbe precisely what the application programmer * should expect in the following, and for that reason I tell the * units and origin of each measurement (where it applies), or else I * use sufficiently weaselly language ("is a monotonically nondecreasing * function of...") that I cannot set false expectations for lawyerly * readers. */ #if defined(__KERNEL__) || defined(_KERNEL) #ifndef DLT_IEEE802_11_RADIO #define DLT_IEEE802_11_RADIO 127 /* 802.11 plus WLAN header */ #endif #endif /* defined(__KERNEL__) || defined(_KERNEL) */ /* kernel 2.4 compat */ #if !defined __le16 #define __le16 u_int16_t #endif #if !defined __le32 #define __le32 u_int32_t #endif /* The radio capture header precedes the 802.11 header. */ struct ieee80211_radiotap_header { u_int8_t it_version; /* Version 0. Only increases * for drastic changes, * introduction of compatible * new fields does not count. */ u_int8_t it_pad; __le16 it_len; /* length of the whole * header in bytes, including * it_version, it_pad, * it_len, and data fields. */ __le32 it_present; /* A bitmap telling which * fields are present. Set bit 31 * (0x80000000) to extend the * bitmap by another 32 bits. * Additional extensions are made * by setting bit 31. */ } __attribute__((__packed__)); /* Name Data type Units * ---- --------- ----- * * IEEE80211_RADIOTAP_TSFT u_int64_t microseconds * * Value in microseconds of the MAC's 64-bit 802.11 Time * Synchronization Function timer when the first bit of the * MPDU arrived at the MAC. For received frames, only. * * IEEE80211_RADIOTAP_CHANNEL 2 x u_int16_t MHz, bitmap * * Tx/Rx frequency in MHz, followed by flags (see below). * * IEEE80211_RADIOTAP_FHSS u_int16_t see below * * For frequency-hopping radios, the hop set (first byte) * and pattern (second byte). * * IEEE80211_RADIOTAP_RATE u_int8_t 500kb/s * * Tx/Rx data rate * * IEEE80211_RADIOTAP_DBM_ANTSIGNAL int8_t decibels from * one milliwatt (dBm) * * RF signal power at the antenna, decibel difference from * one milliwatt. * * IEEE80211_RADIOTAP_DBM_ANTNOISE int8_t decibels from * one milliwatt (dBm) * * RF noise power at the antenna, decibel difference from one * milliwatt. * * IEEE80211_RADIOTAP_DB_ANTSIGNAL u_int8_t decibel (dB) * * RF signal power at the antenna, decibel difference from an * arbitrary, fixed reference. * * IEEE80211_RADIOTAP_DB_ANTNOISE u_int8_t decibel (dB) * * RF noise power at the antenna, decibel difference from an * arbitrary, fixed reference point. * * IEEE80211_RADIOTAP_BARKER_CODE_LOCK u_int16_t unitless * * Quality of Barker code lock. Unitless. Monotonically * nondecreasing with "better" lock strength. Called "Signal * Quality" in datasheets. (Is there a standard way to measure * this?) * * IEEE80211_RADIOTAP_TX_ATTENUATION u_int16_t unitless * * Transmit power expressed as unitless distance from max * power set at factory calibration. 0 is max power. * Monotonically nondecreasing with lower power levels. * * IEEE80211_RADIOTAP_DB_TX_ATTENUATION u_int16_t decibels (dB) * * Transmit power expressed as decibel distance from max power * set at factory calibration. 0 is max power. Monotonically * nondecreasing with lower power levels. * * IEEE80211_RADIOTAP_DBM_TX_POWER int8_t decibels from * one milliwatt (dBm) * * Transmit power expressed as dBm (decibels from a 1 milliwatt * reference). This is the absolute power level measured at * the antenna port. * * IEEE80211_RADIOTAP_FLAGS u_int8_t bitmap * * Properties of transmitted and received frames. See flags * defined below. * * IEEE80211_RADIOTAP_ANTENNA u_int8_t antenna index * * Unitless indication of the Rx/Tx antenna for this packet. * The first antenna is antenna 0. * * IEEE80211_RADIOTAP_RX_FLAGS u_int16_t bitmap * * Properties of received frames. See flags defined below. * * IEEE80211_RADIOTAP_TX_FLAGS u_int16_t bitmap * * Properties of transmitted frames. See flags defined below. * * IEEE80211_RADIOTAP_RTS_RETRIES u_int8_t data * * Number of rts retries a transmitted frame used. * * IEEE80211_RADIOTAP_DATA_RETRIES u_int8_t data * * Number of unicast retries a transmitted frame used. */ enum ieee80211_radiotap_type { IEEE80211_RADIOTAP_TSFT = 0, IEEE80211_RADIOTAP_FLAGS = 1, IEEE80211_RADIOTAP_RATE = 2, IEEE80211_RADIOTAP_CHANNEL = 3, IEEE80211_RADIOTAP_FHSS = 4, IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, IEEE80211_RADIOTAP_LOCK_QUALITY = 7, IEEE80211_RADIOTAP_TX_ATTENUATION = 8, IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, IEEE80211_RADIOTAP_DBM_TX_POWER = 10, IEEE80211_RADIOTAP_ANTENNA = 11, IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, IEEE80211_RADIOTAP_DB_ANTNOISE = 13, IEEE80211_RADIOTAP_RX_FLAGS = 14, IEEE80211_RADIOTAP_TX_FLAGS = 15, IEEE80211_RADIOTAP_RTS_RETRIES = 16, IEEE80211_RADIOTAP_DATA_RETRIES = 17, IEEE80211_RADIOTAP_EXT = 31, }; #ifndef _KERNEL /* Channel flags. */ #define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */ #define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */ #define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */ #define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */ #define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */ #define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ #define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */ #define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */ /* Useful combinations of channel characteristics, borrowed from Ethereal */ #define IEEE80211_CHAN_A \ (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM) #define IEEE80211_CHAN_B \ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK) #define IEEE80211_CHAN_G \ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN) #define IEEE80211_CHAN_TA \ (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO) #define IEEE80211_CHAN_TG \ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN | IEEE80211_CHAN_TURBO) #endif /* !_KERNEL */ /* For IEEE80211_RADIOTAP_FLAGS */ #define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received * during CFP */ #define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received * with short * preamble */ #define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received * with WEP encryption */ #define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received * with fragmentation */ #define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */ #define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between * 802.11 header and payload * (to 32-bit boundary) */ #define IEEE80211_RADIOTAP_F_BADFCS 0x40 /* does not pass FCS check */ /* For IEEE80211_RADIOTAP_RX_FLAGS */ #define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* Frame failed CRC check. * * Deprecated: use the flag * IEEE80211_RADIOTAP_F_FCS in * the IEEE80211_RADIOTAP_FLAGS * field, instead. */ /* For IEEE80211_RADIOTAP_TX_FLAGS */ #define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive * retries */ #define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ #define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ #endif /* _NET_IF_IEEE80211RADIOTAP_H_ */ horst-3.0/ieee80211_util.c000066400000000000000000000211671152373700300152270ustar00rootroot00000000000000/* copied from linux wireless-2.6/net/mac80211/util.c */ /* * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc * Copyright 2007 Johannes Berg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * utilities for mac80211 */ #include #include #include #include "ieee80211.h" #include "ieee80211_radiotap.h" #include "ieee80211_util.h" #include "main.h" #include "util.h" u8* ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len) { __le16 fc; if (len < 24) return NULL; fc = le16_to_cpu(hdr->frame_control); switch (fc & IEEE80211_FCTL_FTYPE) { case IEEE80211_FTYPE_DATA: switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { case IEEE80211_FCTL_TODS: return hdr->addr1; case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS): return NULL; case IEEE80211_FCTL_FROMDS: return hdr->addr2; case 0: return hdr->addr3; } break; case IEEE80211_FTYPE_MGMT: return hdr->addr3; case IEEE80211_FTYPE_CTL: if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL) return hdr->addr1; else return NULL; } return NULL; } int ieee80211_get_hdrlen(u16 fc) { int hdrlen = 24; switch (fc & IEEE80211_FCTL_FTYPE) { case IEEE80211_FTYPE_DATA: if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) hdrlen = 30; /* Addr4 */ /* * The QoS Control field is two bytes and its presence is * indicated by the IEEE80211_STYPE_QOS_DATA bit. Add 2 to * hdrlen if that bit is set. * This works by masking out the bit and shifting it to * bit position 1 so the result has the value 0 or 2. */ hdrlen += (fc & IEEE80211_STYPE_QOS_DATA) >> 6; break; case IEEE80211_FTYPE_CTL: /* * ACK and CTS are 10 bytes, all others 16. To see how * to get this condition consider * subtype mask: 0b0000000011110000 (0x00F0) * ACK subtype: 0b0000000011010000 (0x00D0) * CTS subtype: 0b0000000011000000 (0x00C0) * bits that matter: ^^^ (0x00E0) * value of those: 0b0000000011000000 (0x00C0) */ if ((fc & 0xE0) == 0xC0) hdrlen = 10; else hdrlen = 16; break; } return hdrlen; } /* from mac80211/ieee80211_sta.c, modified */ void ieee802_11_parse_elems(unsigned char *start, size_t len, struct packet_info *p) { int left = len; unsigned char *pos = start; while (left >= 2) { u8 id, elen; id = *pos++; elen = *pos++; left -= 2; if (elen > left) return; switch (id) { case WLAN_EID_SSID: memcpy(p->wlan_essid, pos, elen); break; #if 0 case WLAN_EID_SUPP_RATES: elems->supp_rates = pos; elems->supp_rates_len = elen; break; case WLAN_EID_FH_PARAMS: elems->fh_params = pos; elems->fh_params_len = elen; break; #endif case WLAN_EID_DS_PARAMS: p->wlan_channel = *pos; break; #if 0 case WLAN_EID_CF_PARAMS: elems->cf_params = pos; elems->cf_params_len = elen; break; case WLAN_EID_TIM: elems->tim = pos; elems->tim_len = elen; break; case WLAN_EID_IBSS_PARAMS: elems->ibss_params = pos; elems->ibss_params_len = elen; break; case WLAN_EID_CHALLENGE: elems->challenge = pos; elems->challenge_len = elen; break; case WLAN_EID_WPA: if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && pos[2] == 0xf2) { /* Microsoft OUI (00:50:F2) */ if (pos[3] == 1) { /* OUI Type 1 - WPA IE */ elems->wpa = pos; elems->wpa_len = elen; } else if (elen >= 5 && pos[3] == 2) { if (pos[4] == 0) { elems->wmm_info = pos; elems->wmm_info_len = elen; } else if (pos[4] == 1) { elems->wmm_param = pos; elems->wmm_param_len = elen; } } } break; case WLAN_EID_RSN: elems->rsn = pos; elems->rsn_len = elen; break; case WLAN_EID_ERP_INFO: elems->erp_info = pos; elems->erp_info_len = elen; break; case WLAN_EID_EXT_SUPP_RATES: elems->ext_supp_rates = pos; elems->ext_supp_rates_len = elen; break; #endif default: break; } left -= elen; pos += elen; } } /* from mac80211/ieee80211_i.c, slightly modified */ /** * ieee80211_is_erp_rate - Check if a rate is an ERP rate * @phymode: The PHY-mode for this rate (MODE_IEEE80211...) * @rate: Transmission rate to check, in 100 kbps * * Check if a given rate is an Extended Rate PHY (ERP) rate. */ static inline int ieee80211_is_erp_rate(int phymode, int rate) { if (phymode & PHY_FLAG_G) { if (rate != 10 && rate != 20 && rate != 55 && rate != 110) { DEBUG("erp\n"); return 1; } } DEBUG("no erp\n"); return 0; } int get_cw_time(int cw_min, int cw_max, int retries, int slottime) { int cw = pow(2, (cw_min + retries)) - 1; cw_max = pow(2, cw_max) - 1; if(cw > cw_max) cw = cw_max; DEBUG("CW min %d max %d ret %d = %d\n", cw_min, cw_max, retries, cw); return (cw * slottime) / 2; } const unsigned char ieee802_1d_to_ac[8] = { 0, 1, 1, 0, 2, 2, 3, 3 }; /* BE BK VI VO */ const unsigned char ac_to_aifs[4] = { 3, 7, 2, 2}; const unsigned char ac_to_cwmin[4] = { 4, 4, 3, 2}; const unsigned int ac_to_cwmax[4] = { 10, 10, 4, 3}; /* from mac80211/util.c, modified */ int ieee80211_frame_duration(int phymode, size_t len, int rate, int short_preamble, int shortslot, int type, char qos_class, int retries) { int dur; int erp; int sifs, slottime; static int last_was_cts; erp = ieee80211_is_erp_rate(phymode, rate); /* calculate duration (in microseconds, rounded up to next higher * integer if it includes a fractional microsecond) to send frame of * len bytes (does not include FCS) at the given rate. Duration will * also include SIFS. * * rate is in 100 kbps, so divident is multiplied by 10 in the * DIV_ROUND_UP() operations. */ DEBUG("DUR mode %d, len %d, rate %d, shortpre %d shortslot %d type %x UP %d\n", phymode, (int)len, rate, short_preamble, shortslot, type, qos_class); if (phymode == PHY_FLAG_A || erp) { DEBUG("OFDM\n"); /* * OFDM: * * N_DBPS = DATARATE x 4 * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS) * (16 = SIGNAL time, 6 = tail bits) * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext * * T_SYM = 4 usec * 802.11a - 17.5.2: aSIFSTime = 16 usec * 802.11g - 19.8.4: aSIFSTime = 10 usec + * signal ext = 6 usec */ sifs = 16; /* SIFS + signal ext */ slottime = 9; dur = 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */ dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */ dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10, 4 * rate); /* T_SYM x N_SYM */ } else { DEBUG("CCK\n"); /* * 802.11b or 802.11g with 802.11b compatibility: * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime + * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0. * * 802.11 (DS): 15.3.3, 802.11b: 18.3.4 * aSIFSTime = 10 usec * aPreambleLength = 144 usec or 72 usec with short preamble * aPLCPHeaderLength = 48 usec or 24 usec with short preamble */ sifs = 10; /* aSIFSTime = 10 usec */ slottime = shortslot ? 9 : 20; dur = short_preamble ? (72 + 24) : (144 + 48); dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate); } if (IEEE80211_IS_CTRL_STYPE(type, IEEE80211_STYPE_CTS) || IEEE80211_IS_CTRL_STYPE(type, IEEE80211_STYPE_ACK)) { //TODO: also fragments DEBUG("DUR SIFS\n"); dur += sifs; } else if (IEEE80211_IS_MGMT_STYPE(type, IEEE80211_STYPE_BEACON)) { /* TODO: which AIFS and CW should be used for beacons? */ dur += sifs + (2 * slottime); /* AIFS */ dur += (slottime * 1) / 2; /* contention */ } else if (IEEE80211_IS_DATA(type) && last_was_cts) { DEBUG("DUR LAST CTS\n"); dur += sifs; } else if (IEEE80211_IS_DATA_STYPE(type, IEEE80211_STYPE_QOS_DATA)) { unsigned char ac = ieee802_1d_to_ac[(unsigned char)qos_class]; dur += sifs + (ac_to_aifs[ac] * slottime); /* AIFS */ dur += get_cw_time(ac_to_cwmin[ac], ac_to_cwmax[ac], retries, slottime); DEBUG("DUR AIFS %d CWMIN %d AC %d, UP %d\n", ac_to_aifs[ac], ac_to_cwmin[ac], ac, qos_class); } else { DEBUG("DUR DIFS\n"); dur += sifs + (2 * slottime); /* DIFS */ dur += get_cw_time(4, 10, retries, slottime); } if (IEEE80211_IS_CTRL_STYPE(type, IEEE80211_STYPE_CTS)) { DEBUG("SET CTS\n"); last_was_cts = 1; } else last_was_cts = 0; /* TODO: Add EIFS (SIFS + ACKTXTIME) to frames with CRC errors, if we can get them */ DEBUG("DUR %d\n", dur); return dur; } int ieee80211_frequency_to_channel(int freq) { int base; if (freq == 2484) return 14; if (freq < 2484) base = 2407; else if (freq >= 4910 && freq <= 4980) base = 4000; else base = 5000; return (freq - base) / 5; } horst-3.0/ieee80211_util.h000066400000000000000000000017311152373700300152270ustar00rootroot00000000000000/* copied from linux wireless-2.6/net/mac80211/util.c */ /* * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc * Copyright 2007 Johannes Berg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * utilities for mac80211 */ #ifndef _IEEE80211_UTIL_H_ #define _IEEE80211_UTIL_H_ #include "ieee80211.h" struct packet_info; int ieee80211_get_hdrlen(u16 fc); u8* ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len); void ieee802_11_parse_elems(unsigned char *start, size_t len, struct packet_info *pkt); int ieee80211_frame_duration(int phymode, size_t len, int rate, int short_preamble, int ackcts, int shortslot, char qos_class, int retries); int ieee80211_frequency_to_channel(int freq); #endif horst-3.0/list.h000066400000000000000000000372261152373700300136520ustar00rootroot00000000000000#ifndef _LINUX_LIST_H #define _LINUX_LIST_H #include /* * Simple doubly linked list implementation (lifted from the * Linux kernel) * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ struct list_head { struct list_head *next, *prev; }; /** * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member. * @type: the type of the container struct this is embedded in. * @member: the name of the member within the struct. * */ #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) static inline void INIT_LIST_HEAD(struct list_head *list) { list->next = list; list->prev = list; } /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { next->prev = new; new->next = next; new->prev = prev; prev->next = new; } /** * list_add - add a new entry * @new: new entry to be added * @head: list head to add it after * * Insert a new entry after the specified head. * This is good for implementing stacks. */ static inline void list_add(struct list_head *new, struct list_head *head) { __list_add(new, head, head->next); } /** * list_add_tail - add a new entry * @new: new entry to be added * @head: list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */ static inline void list_add_tail(struct list_head *new, struct list_head *head) { __list_add(new, head->prev, head); } /* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_del(struct list_head * prev, struct list_head * next) { next->prev = prev; prev->next = next; } /** * list_del - deletes entry from list. * @entry: the element to delete from the list. * Note: list_empty() on entry does not return true after this, the entry is * in an undefined state. */ static inline void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); } /** * list_replace - replace old entry by new one * @old : the element to be replaced * @new : the new element to insert * * If @old was empty, it will be overwritten. */ static inline void list_replace(struct list_head *old, struct list_head *new) { new->next = old->next; new->next->prev = new; new->prev = old->prev; new->prev->next = new; } static inline void list_replace_init(struct list_head *old, struct list_head *new) { list_replace(old, new); INIT_LIST_HEAD(old); } /** * list_del_init - deletes entry from list and reinitialize it. * @entry: the element to delete from the list. */ static inline void list_del_init(struct list_head *entry) { __list_del(entry->prev, entry->next); INIT_LIST_HEAD(entry); } /** * list_move - delete from one list and add as another's head * @list: the entry to move * @head: the head that will precede our entry */ static inline void list_move(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_add(list, head); } /** * list_move_tail - delete from one list and add as another's tail * @list: the entry to move * @head: the head that will follow our entry */ static inline void list_move_tail(struct list_head *list, struct list_head *head) { __list_del(list->prev, list->next); list_add_tail(list, head); } /** * list_is_last - tests whether @list is the last entry in list @head * @list: the entry to test * @head: the head of the list */ static inline int list_is_last(const struct list_head *list, const struct list_head *head) { return list->next == head; } /** * list_empty - tests whether a list is empty * @head: the list to test. */ static inline int list_empty(const struct list_head *head) { return head->next == head; } static inline void __list_splice(struct list_head *list, struct list_head *head) { struct list_head *first = list->next; struct list_head *last = list->prev; struct list_head *at = head->next; first->prev = head; head->next = first; last->next = at; at->prev = last; } /** * list_splice - join two lists * @list: the new list to add. * @head: the place to add it in the first list. */ static inline void list_splice(struct list_head *list, struct list_head *head) { if (!list_empty(list)) __list_splice(list, head); } /** * list_splice_init - join two lists and reinitialise the emptied list. * @list: the new list to add. * @head: the place to add it in the first list. * * The list at @list is reinitialised */ static inline void list_splice_init(struct list_head *list, struct list_head *head) { if (!list_empty(list)) { __list_splice(list, head); INIT_LIST_HEAD(list); } } /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. */ #define list_entry(ptr, type, member) \ container_of(ptr, type, member) /** * list_first_entry - get the first element from a list * @ptr: the list head to take the element from. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. * * Note, that list is expected to be not empty. */ #define list_first_entry(ptr, type, member) \ list_entry((ptr)->next, type, member) /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. */ #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); \ pos = pos->next) /** * __list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. * * This variant differs from list_for_each() in that it's the * simplest possible list iteration code, no prefetching is done. * Use this for code that knows the list to be very short (empty * or 1 entry) most of the time. */ #define __list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) /** * list_for_each_prev - iterate over a list backwards * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. */ #define list_for_each_prev(pos, head) \ for (pos = (head)->prev; pos != (head); \ pos = pos->prev) /** * list_for_each_safe - iterate over a list safe against removal of list entry * @pos: the &struct list_head to use as a loop cursor. * @n: another &struct list_head to use as temporary storage * @head: the head for your list. */ #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) /** * list_for_each_entry - iterate over list of given type * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_reverse - iterate backwards over list of given type. * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_reverse(pos, head, member) \ for (pos = list_entry((head)->prev, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.prev, typeof(*pos), member)) /** * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() * @pos: the type * to use as a start point * @head: the head of the list * @member: the name of the list_struct within the struct. * * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). */ #define list_prepare_entry(pos, head, member) \ ((pos) ? : list_entry(head, typeof(*pos), member)) /** * list_for_each_entry_continue - continue iteration over list of given type * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Continue to iterate over list of given type, continuing after * the current position. */ #define list_for_each_entry_continue(pos, head, member) \ for (pos = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_from - iterate over list of given type from the current point * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate over list of given type, continuing from current position. */ #define list_for_each_entry_from(pos, head, member) \ for (; &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) /** * list_for_each_entry_safe_continue * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate over list of given type, continuing after current point, * safe against removal of list entry. */ #define list_for_each_entry_safe_continue(pos, n, head, member) \ for (pos = list_entry(pos->member.next, typeof(*pos), member), \ n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) /** * list_for_each_entry_safe_from * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate over list of given type from current point, safe against * removal of list entry. */ #define list_for_each_entry_safe_from(pos, n, head, member) \ for (n = list_entry(pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) /** * list_for_each_entry_safe_reverse * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate backwards over list of given type, safe against removal * of list entry. */ #define list_for_each_entry_safe_reverse(pos, n, head, member) \ for (pos = list_entry((head)->prev, typeof(*pos), member), \ n = list_entry(pos->member.prev, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry(n->member.prev, typeof(*n), member)) /* * Double linked lists with a single pointer list head. * Mostly useful for hash tables where the two pointer list head is * too wasteful. * You lose the ability to access the tail in O(1). */ struct hlist_head { struct hlist_node *first; }; struct hlist_node { struct hlist_node *next, **pprev; }; #define HLIST_HEAD_INIT { .first = NULL } #define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } #define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) static inline void INIT_HLIST_NODE(struct hlist_node *h) { h->next = NULL; h->pprev = NULL; } static inline int hlist_unhashed(const struct hlist_node *h) { return !h->pprev; } static inline int hlist_empty(const struct hlist_head *h) { return !h->first; } static inline void __hlist_del(struct hlist_node *n) { struct hlist_node *next = n->next; struct hlist_node **pprev = n->pprev; *pprev = next; if (next) next->pprev = pprev; } static inline void hlist_del(struct hlist_node *n) { __hlist_del(n); } static inline void hlist_del_init(struct hlist_node *n) { if (!hlist_unhashed(n)) { __hlist_del(n); INIT_HLIST_NODE(n); } } static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) { struct hlist_node *first = h->first; n->next = first; if (first) first->pprev = &n->next; h->first = n; n->pprev = &h->first; } /* next must be != NULL */ static inline void hlist_add_before(struct hlist_node *n, struct hlist_node *next) { n->pprev = next->pprev; n->next = next; next->pprev = &n->next; *(n->pprev) = n; } static inline void hlist_add_after(struct hlist_node *n, struct hlist_node *next) { next->next = n->next; n->next = next; next->pprev = &n->next; if(next->next) next->next->pprev = &next->next; } #define hlist_entry(ptr, type, member) container_of(ptr,type,member) #define hlist_for_each(pos, head) \ for (pos = (head)->first; pos; \ pos = pos->next) #define hlist_for_each_safe(pos, n, head) \ for (pos = (head)->first; pos; \ pos = n) /** * hlist_for_each_entry - iterate over list of given type * @tpos: the type * to use as a loop cursor. * @pos: the &struct hlist_node to use as a loop cursor. * @head: the head for your list. * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry(tpos, pos, head, member) \ for (pos = (head)->first; \ pos && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = pos->next) /** * hlist_for_each_entry_continue - iterate over a hlist continuing after current point * @tpos: the type * to use as a loop cursor. * @pos: the &struct hlist_node to use as a loop cursor. * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry_continue(tpos, pos, member) \ for (pos = (pos)->next; \ pos && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = pos->next) /** * hlist_for_each_entry_from - iterate over a hlist continuing from current point * @tpos: the type * to use as a loop cursor. * @pos: the &struct hlist_node to use as a loop cursor. * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry_from(tpos, pos, member) \ for (; pos && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = pos->next) /** * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry * @tpos: the type * to use as a loop cursor. * @pos: the &struct hlist_node to use as a loop cursor. * @n: another &struct hlist_node to use as temporary storage * @head: the head for your list. * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ for (pos = (head)->first; \ pos && ({ n = pos->next; 1; }) && \ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ pos = n) #endif horst-3.0/listsort.c000066400000000000000000000161711152373700300145510ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * This is based on work under the following license: * * This file is copyright 2001 Simon Tatham. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "list.h" #include "listsort.h" /* * sorting a linked list. * * The algorithm used is Mergesort, because that works really well * on linked lists, without requiring the O(N) extra space it needs * when you do it on arrays. * */ /* * This is the actual sort function. * It assumes head to be a pointer to the first list element, and not beeing a * list element itself (as common in the linux linked list implementation). * If the first element moves, head is adjusted accordingly. */ void listsort(struct list_head *head, int(*cmp)(const struct list_head*, const struct list_head*)) { struct list_head *list, *p, *q, *e, *tail, *oldhead; int insize, nmerges, psize, qsize, i; if (!head || head->next == head) return; list = head->next; insize = 1; while (1) { p = list; oldhead = list; /* used for circular linkage */ list = NULL; tail = NULL; nmerges = 0; /* count number of merges we do in this pass */ while (p) { nmerges++; /* there exists a merge to be done */ /* step `insize' places along from p */ q = p; psize = 0; for (i = 0; i < insize; i++) { psize++; q = (q->next == oldhead || q->next == head ? NULL : q->next); if (!q) break; } /* if q hasn't fallen off end, we have two lists to merge */ qsize = insize; /* now we have two lists; merge them */ while (psize > 0 || (qsize > 0 && q)) { /* decide whether next element of merge comes from p or q */ if (psize == 0) { /* p is empty; e must come from q. */ e = q; q = q->next; qsize--; if (q == oldhead || q == head) q = NULL; } else if (qsize == 0 || !q) { /* q is empty; e must come from p. */ e = p; p = p->next; psize--; if (p == oldhead || p == head) p = NULL; } else if (cmp(p,q) <= 0) { /* First element of p is lower (or same); * e must come from p. */ e = p; p = p->next; psize--; if (p == oldhead || p == head) p = NULL; } else { /* First element of q is lower; e must come from q. */ e = q; q = q->next; qsize--; if (q == oldhead || q == head) q = NULL; } /* add the next element to the merged list */ if (tail) tail->next = e; else list = e; /* Maintain reverse pointers */ e->prev = tail; tail = e; } /* now p has stepped `insize' places along, and q has too */ p = q; } tail->next = list; list->prev = tail; /* If we have done only one merge, we're finished. */ if (nmerges <= 1) { /* allow for nmerges==0, the empty list case */ /* adjust head */ head->next = list; head->prev = list->prev; list->prev->next = head; list->prev = head; return; } /* Otherwise repeat, merging lists twice the size */ insize *= 2; } } #if 0 /* * Small test rig with three test orders. The list length 13 is * chosen because that means some passes will have an extra list at * the end and some will not. */ #include struct element { struct list_head list; int i; }; int elem_cmp(const struct list_head *a, const struct list_head *b) { struct element *ea = list_entry(a, struct element, list); struct element *eb = list_entry(b, struct element, list); //printf(" cmp %d - %d\n", ea->i, eb->i); return ea->i - eb->i; } #if 0 /* old outdated test */ int main(void) { #define n 13 struct element k[n], *head, *p; struct list_head* lh; int order[][n] = { { 0,1,2,3,4,5,6,7,8,9,10,11,12 }, { 6,2,8,4,11,1,12,7,3,9,5,0,10 }, { 12,11,10,9,8,7,6,5,4,3,2,1,0 }, }; int i, j; for (j = 0; j < n; j++) k[j].i = j; listsort(NULL, &elem_cmp); for (i = 0; i < sizeof(order)/sizeof(*order); i++) { int *ord = order[i]; head = &k[ord[0]]; for (j = 0; j < n; j++) { if (j == n-1) k[ord[j]].list.next = &k[ord[0]].list; else k[ord[j]].list.next = &k[ord[j+1]].list; if (j == 0) k[ord[j]].list.prev = &k[ord[n-1]].list; else k[ord[j]].list.prev = &k[ord[j-1]].list; } printf("before:"); p = head; do { printf(" %d", p->i); //if (p->list.next && p->list.next->prev != p->list) // printf(" [REVERSE LINK ERROR!]"); p = list_entry(p->list.next, struct element, list); } while (p != head); printf("\n"); lh = listsort(&head->list, &elem_cmp); head = list_entry(lh, struct element, list); printf(" after:"); p = head; do { printf(" %d", p->i); //if (p->next && p->next->prev != p) // printf(" [REVERSE LINK ERROR!]"); p = list_entry(p->list.next, struct element, list); } while (p != head); printf("\n"); } return 0; } #endif int main(void) { struct list_head lh; struct element e[5]; struct element* ep; INIT_LIST_HEAD(&lh); e[0].i = 5; e[1].i = 2; e[2].i = 1; e[3].i = 3; e[4].i = 4; list_add_tail(&e[0].list, &lh); list_add_tail(&e[1].list, &lh); list_add_tail(&e[2].list, &lh); list_add_tail(&e[3].list, &lh); list_add_tail(&e[4].list, &lh); list_for_each_entry(ep, &lh, list) { printf("%d ", ep->i); } printf("\n"); listsort(&lh, &elem_cmp); list_for_each_entry(ep, &lh, list) { printf("%d ", ep->i); //printf(" [%p next %p prev %p]\n", &ep->list, ep->list.next, ep->list.prev); if (ep->list.next->prev != &ep->list) printf("* reverse link error!\n"); } printf("\n"); return 0; } #endif horst-3.0/listsort.h000066400000000000000000000017561152373700300145610ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _LISTSORT_H #define _LISTSORT_H struct list_head; void listsort(struct list_head *list, int(*cmp)(const struct list_head*, const struct list_head*)); #endif horst-3.0/main.c000066400000000000000000000375511152373700300136170ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include "main.h" #include "util.h" #include "capture.h" #include "protocol_parser.h" #include "network.h" #include "display.h" #include "ieee80211.h" #include "ieee80211_util.h" #include "wext.h" struct list_head nodes; struct essid_meta_info essids; struct history hist; struct statistics stats; struct chan_freq channels[MAX_CHANNELS]; struct channel_info spectrum[MAX_CHANNELS]; struct config conf = { .node_timeout = NODE_TIMEOUT, .channel_time = CHANNEL_TIME, .ifname = INTERFACE_NAME, .display_interval = DISPLAY_UPDATE_INTERVAL, .filter_pkt = 0xffffff, .recv_buffer_size = RECV_BUFFER_SIZE, .port = DEFAULT_PORT, }; struct timeval the_time; int mon; /* monitoring socket */ static FILE* DF = NULL; /* receive packet buffer * * due to the way we receive packets the network (TCP connection) we have to * expect the reception of partial packet as well as the reception of several * packets at one. thus we implement a buffered receive where partially received * data stays in the buffer. * * we need two buffers: one for packet capture or receiving from the server and * another one for data the clients sends to the server. * * not sure if this is also an issue with local packet capture, but it is not * implemented there. * * size: max 80211 frame (2312) + space for prism2 header (144) * or radiotap header (usually only 26) + some extra */ static unsigned char buffer[2312 + 200]; static size_t buflen; /* for packets from client to server */ static unsigned char cli_buffer[500]; static size_t cli_buflen; /* for select */ static fd_set read_fds; static fd_set write_fds; static fd_set excpt_fds; static struct timeval tv; struct node_info* node_update(struct packet_info* p); void update_essids(struct packet_info* p, struct node_info* n); void timeout_nodes(void); int auto_change_channel(int mon); void get_current_channel(int mon); void __attribute__ ((format (printf, 1, 2))) printlog(const char *fmt, ...) { char buf[128]; va_list ap; va_start(ap, fmt); vsnprintf(&buf[1], 127, fmt, ap); va_end(ap); if (conf.quiet || DO_DEBUG || !conf.display_initialized) printf("%s\n", &buf[1]); else { /* fix up string for display log */ buf[0] = '\n'; display_log(buf); } } static void update_history(struct packet_info* p) { if (p->phy_signal == 0) return; hist.signal[hist.index] = p->phy_signal; hist.noise[hist.index] = p->phy_noise; hist.rate[hist.index] = p->phy_rate; hist.type[hist.index] = p->wlan_type; hist.retry[hist.index] = p->wlan_retry; hist.index++; if (hist.index == MAX_HISTORY) hist.index = 0; } static void update_statistics(struct packet_info* p) { if (p->phy_rate == 0) return; stats.packets++; stats.bytes += p->wlan_len; if (p->wlan_retry) stats.retries++; if (p->phy_rate > 0 && p->phy_rate < MAX_RATES) { stats.duration += p->pkt_duration; stats.packets_per_rate[p->phy_rate]++; stats.bytes_per_rate[p->phy_rate] += p->wlan_len; stats.duration_per_rate[p->phy_rate] += p->pkt_duration; } if (p->wlan_type >= 0 && p->wlan_type < MAX_FSTYPE) { stats.packets_per_type[p->wlan_type]++; stats.bytes_per_type[p->wlan_type] += p->wlan_len; if (p->phy_rate > 0 && p->phy_rate < MAX_RATES) stats.duration_per_type[p->wlan_type] += p->pkt_duration; } } static void update_spectrum(struct packet_info* p, struct node_info* n) { struct channel_info* chan; struct chan_node* cn; if (p->pkt_chan_idx < 0) return; /* chan not found */ chan = &spectrum[p->pkt_chan_idx]; chan->signal = p->phy_signal; chan->noise = p->phy_noise; chan->packets++; chan->bytes += p->wlan_len; chan->durations += p->pkt_duration; ewma_add(&chan->signal_avg, -chan->signal); if (!n) return; /* add node to channel if not already there */ list_for_each_entry(cn, &chan->nodes, chan_list) { if (cn->node == n) { DEBUG("SPEC node found %p\n", cn->node); break; } } if (cn->node != n) { DEBUG("SPEC node adding %p\n", n); cn = malloc(sizeof(struct chan_node)); cn->node = n; cn->chan = chan; ewma_init(&cn->sig_avg, 1024, 8); list_add_tail(&cn->chan_list, &chan->nodes); list_add_tail(&cn->node_list, &n->on_channels); chan->num_nodes++; n->num_on_channels++; } /* keep signal of this node as seen on this channel */ cn->sig = p->phy_signal; ewma_add(&cn->sig_avg, -cn->sig); cn->packets++; } void update_spectrum_durations(void) { /* also if channel was not changed, keep stats only for every channel_time. * display code uses durations_last to get a more stable view */ if (conf.current_channel >= 0) { spectrum[conf.current_channel].durations_last = spectrum[conf.current_channel].durations; spectrum[conf.current_channel].durations = 0; ewma_add(&spectrum[conf.current_channel].durations_avg, spectrum[conf.current_channel].durations_last); } } static void write_to_file(struct packet_info* p) { fprintf(DF, "%s, %s, ", get_packet_type_name(p->wlan_type), ether_sprintf(p->wlan_src)); fprintf(DF, "%s, ", ether_sprintf(p->wlan_dst)); fprintf(DF, "%s, ", ether_sprintf(p->wlan_bssid)); fprintf(DF, "%x, %d, %d, %d, %d, %d, ", p->pkt_types, p->phy_signal, p->phy_noise, p->phy_snr, p->wlan_len, p->phy_rate); fprintf(DF, "%016llx, ", (unsigned long long)p->wlan_tsf); fprintf(DF, "%s, %d, %d, %d, ", p->wlan_essid, p->wlan_mode, p->wlan_channel, p->wlan_wep); fprintf(DF, "%s, ", ip_sprintf(p->ip_src)); fprintf(DF, "%s, ", ip_sprintf(p->ip_dst)); fprintf(DF, "%d, %d, %d\n", p->olsr_type, p->olsr_neigh, p->olsr_tc); } static int filter_packet(struct packet_info* p) { int i; if (conf.filter_off) return 0; if (!(p->pkt_types & conf.filter_pkt)) { stats.filtered_packets++; return 1; } if (MAC_NOT_EMPTY(conf.filterbssid) && memcmp(p->wlan_bssid, conf.filterbssid, MAC_LEN) != 0) { stats.filtered_packets++; return 1; } if (conf.do_macfilter) { for (i = 0; i < MAX_FILTERMAC; i++) { if (MAC_NOT_EMPTY(p->wlan_src) && conf.filtermac_enabled[i] && memcmp(p->wlan_src, conf.filtermac[i], MAC_LEN) == 0) { return 0; } } stats.filtered_packets++; return 1; } return 0; } void handle_packet(struct packet_info* p) { struct node_info* n; int i = -1; /* filter on server side only */ if (!conf.serveraddr && filter_packet(p)) { if (!conf.quiet && !conf.paused) update_display_clock(); return; } if (cli_fd != -1) net_send_packet(p); if (conf.dumpfile != NULL) write_to_file(p); if (conf.quiet || conf.paused) return; /* get channel index for packet */ if (p->phy_chan) { /* find channel index from packet channel */ for (i = 0; i < conf.num_channels && i < MAX_CHANNELS; i++) if (channels[i].chan == p->phy_chan) break; } /* not found from pkt, best guess from config but it might be * unknown (-1) too */ if (i < 0 || i >= conf.num_channels || i >= MAX_CHANNELS) p->pkt_chan_idx = conf.current_channel; else p->pkt_chan_idx = i; /* detect if noise reading is present or not */ if (!conf.have_noise && p->phy_noise) conf.have_noise = 1; /* if current channel is unknown (this is a mac80211 bug), guess it from * the packet */ if (conf.current_channel < 0 && p->pkt_chan_idx >= 0) conf.current_channel = p->pkt_chan_idx; n = node_update(p); if (n) p->wlan_retries = n->wlan_retries_last; p->pkt_duration = ieee80211_frame_duration( p->phy_flags & PHY_FLAG_MODE_MASK, p->wlan_len, p->phy_rate * 5, p->phy_flags & PHY_FLAG_SHORTPRE, 0 /*shortslot*/, p->wlan_type, p->wlan_qos_class, p->wlan_retries); update_history(p); update_statistics(p); update_spectrum(p, n); update_essids(p, n); #if !DO_DEBUG update_display(p, n); #endif } static void local_receive_packet(int fd, unsigned char* buffer, size_t bufsize) { int len; struct packet_info p; len = recv_packet(fd, buffer, bufsize); #if DO_DEBUG dump_packet(buffer, len); #endif memset(&p, 0, sizeof(p)); if (!parse_packet(buffer, len, &p)) { DEBUG("parsing failed\n"); return; } handle_packet(&p); } static void receive_any(void) { int ret, mfd; FD_ZERO(&read_fds); FD_ZERO(&write_fds); FD_ZERO(&excpt_fds); FD_SET(0, &read_fds); FD_SET(mon, &read_fds); if (srv_fd != -1) FD_SET(srv_fd, &read_fds); if (cli_fd != -1) FD_SET(cli_fd, &read_fds); tv.tv_sec = 0; tv.tv_usec = min(conf.channel_time, 1000000); mfd = max(mon, srv_fd); mfd = max(mfd, cli_fd) + 1; ret = select(mfd, &read_fds, &write_fds, &excpt_fds, &tv); if (ret == -1 && errno == EINTR) /* interrupted */ return; if (ret == 0) { /* timeout */ if (!conf.quiet && !DO_DEBUG) update_display_clock(); return; } else if (ret < 0) /* error */ err(1, "select()"); /* stdin */ if (FD_ISSET(0, &read_fds) && !conf.quiet) handle_user_input(); /* local packet or client */ if (FD_ISSET(mon, &read_fds)) { if (conf.serveraddr) net_receive(mon, buffer, &buflen, sizeof(buffer)); else local_receive_packet(mon, buffer, sizeof(buffer)); } /* server */ if (srv_fd > -1 && FD_ISSET(srv_fd, &read_fds)) net_handle_server_conn(); /* from client to server */ if (cli_fd > -1 && FD_ISSET(cli_fd, &read_fds)) net_receive(cli_fd, cli_buffer, &cli_buflen, sizeof(cli_buffer)); } void free_lists(void) { int i; struct essid_info *e, *f; struct node_info *ni, *mi; struct chan_node *cn, *cn2; /* free node list */ list_for_each_entry_safe(ni, mi, &nodes, list) { DEBUG("free node %s\n", ether_sprintf(ni->last_pkt.wlan_src)); list_del(&ni->list); free(ni); } /* free essids */ list_for_each_entry_safe(e, f, &essids.list, list) { DEBUG("free essid '%s'\n", e->essid); list_del(&e->list); free(e); } /* free channel nodes */ for (i = 0; i < conf.num_channels; i++) { list_for_each_entry_safe(cn, cn2, &spectrum[i].nodes, chan_list) { DEBUG("free chan_node %p\n", cn); list_del(&cn->chan_list); cn->chan->num_nodes--; free(cn); } } } static void finish_all(void) { free_lists(); if (!conf.serveraddr) close_packet_socket(mon, conf.ifname); if (DF != NULL) fclose(DF); #if !DO_DEBUG net_finish(); if (!conf.quiet) finish_display(); #endif } static void exit_handler(void) { finish_all(); } static void sigint_handler(int sig) { exit(0); } static void sigpipe_handler(int sig) { /* ignore signal here - we will handle it after write failed */ } static void get_options(int argc, char** argv) { int c; static int n; while((c = getopt(argc, argv, "hqsCi:t:c:p:e:d:o:b:")) > 0) { switch (c) { case 'p': conf.port = optarg; break; case 'q': conf.quiet = 1; break; case 'i': conf.ifname = optarg; break; case 'o': conf.dumpfile = optarg; break; case 't': conf.node_timeout = atoi(optarg); break; case 'b': conf.recv_buffer_size = atoi(optarg); break; case 's': conf.do_change_channel = 1; break; case 'd': conf.display_interval = atoi(optarg) * 1000; break; case 'e': if (n >= MAX_FILTERMAC) break; conf.do_macfilter = 1; convert_string_to_mac(optarg, conf.filtermac[n]); conf.filtermac_enabled[n] = 1; n++; break; case 'c': conf.serveraddr = optarg; break; case 'C': conf.allow_client = 1; break; case 'h': default: printf("usage: %s [-h] [-q] [-s] [-i interface] [-t sec] [-c IP] [-C] [-p port] [-e mac] [-d ms] [-o file] [-b bytes]\n\n" "Options (default value)\n" " -h\t\tthis help\n" " -q\t\tquiet\n" " -s\t\tspectrum analyzer\n" " -i \tinterface (wlan0)\n" " -t \tnode timeout (60)\n" " -c \tconnect to server\n" " -C allow client connection (server)\n" " -p \tuse port (4444)\n" " -e \tfilter all macs except these (multiple)\n" " -d \tdisplay update interval (100)\n" " -o \twrite packet info into file\n" " -b \treceive buffer size (not set)\n" "\n", argv[0]); exit(0); break; } } } int main(int argc, char** argv) { INIT_LIST_HEAD(&essids.list); INIT_LIST_HEAD(&nodes); get_options(argc, argv); signal(SIGINT, sigint_handler); signal(SIGPIPE, sigpipe_handler); atexit(exit_handler); gettimeofday(&stats.stats_time, NULL); gettimeofday(&the_time, NULL); conf.current_channel = -1; if (conf.serveraddr) mon = net_open_client_socket(conf.serveraddr, conf.port); else { mon = open_packet_socket(conf.ifname, sizeof(buffer), conf.recv_buffer_size); if (mon <= 0) err(1, "Couldn't open packet socket"); conf.arphrd = device_get_arptype(mon, conf.ifname); if (conf.arphrd != ARPHRD_IEEE80211_PRISM && conf.arphrd != ARPHRD_IEEE80211_RADIOTAP) { printf("Wrong monitor type! Please use radiotap or prism2 headers\n"); exit(1); } /* get available channels */ conf.num_channels = wext_get_channels(mon, conf.ifname, channels); init_channels(); get_current_channel(mon); } if (!conf.quiet && !DO_DEBUG) init_display(); if (conf.dumpfile != NULL) { DF = fopen(conf.dumpfile, "w"); if (DF == NULL) err(1, "Couldn't open dump file"); } if (!conf.serveraddr && conf.port && conf.allow_client) net_init_server_socket(conf.port); for ( /* ever */ ;;) { receive_any(); gettimeofday(&the_time, NULL); timeout_nodes(); if (!conf.serveraddr) { /* server */ if (auto_change_channel(mon)) { net_send_channel_config(); update_spectrum_durations(); update_display(NULL, NULL); } } } /* will never */ return 0; } #if 0 void print_rate_duration_table(void) { int i; printf("LEN\t1M l\t1M s\t2M l\t2M s\t5.5M l\t5.5M s\t11M l\t11M s\t"); printf("6M\t9\t12M\t18M\t24M\t36M\t48M\t54M\n"); for (i=10; i<=2304; i+=10) { printf("%d:\t%d\t%d\t", i, ieee80211_frame_duration(PHY_FLAG_G, i, 10, 0, 0, IEEE80211_FTYPE_DATA, 0, 0), ieee80211_frame_duration(PHY_FLAG_G, i, 10, 1, 0, IEEE80211_FTYPE_DATA, 0, 0)); printf("%d\t%d\t", ieee80211_frame_duration(PHY_FLAG_G, i, 20, 0, 0, IEEE80211_FTYPE_DATA, 0, 0), ieee80211_frame_duration(PHY_FLAG_G, i, 20, 1, 0, IEEE80211_FTYPE_DATA, 0, 0)); printf("%d\t%d\t", ieee80211_frame_duration(PHY_FLAG_G, i, 55, 0, 0, IEEE80211_FTYPE_DATA, 0, 0), ieee80211_frame_duration(PHY_FLAG_G, i, 55, 1, 0, IEEE80211_FTYPE_DATA, 0, 0)); printf("%d\t%d\t", ieee80211_frame_duration(PHY_FLAG_G, i, 110, 0, 0, IEEE80211_FTYPE_DATA, 0, 0), ieee80211_frame_duration(PHY_FLAG_G, i, 110, 1, 0, IEEE80211_FTYPE_DATA, 0, 0)); printf("%d\t", ieee80211_frame_duration(PHY_FLAG_G, i, 60, 1, 0, IEEE80211_FTYPE_DATA, 0, 0)); printf("%d\t", ieee80211_frame_duration(PHY_FLAG_G, i, 90, 1, 0, IEEE80211_FTYPE_DATA, 0, 0)); printf("%d\t", ieee80211_frame_duration(PHY_FLAG_G, i, 120, 1, 0, IEEE80211_FTYPE_DATA, 0, 0)), printf("%d\t", ieee80211_frame_duration(PHY_FLAG_G, i, 180, 1, 0, IEEE80211_FTYPE_DATA, 0, 0)), printf("%d\t", ieee80211_frame_duration(PHY_FLAG_G, i, 240, 1, 0, IEEE80211_FTYPE_DATA, 0, 0)), printf("%d\t", ieee80211_frame_duration(PHY_FLAG_G, i, 360, 1, 0, IEEE80211_FTYPE_DATA, 0, 0)); printf("%d\t", ieee80211_frame_duration(PHY_FLAG_G, i, 480, 1, 0, IEEE80211_FTYPE_DATA, 0, 0)), printf("%d\n", ieee80211_frame_duration(PHY_FLAG_G, i, 540, 1, 0, IEEE80211_FTYPE_DATA, 0, 0)); } } #endif horst-3.0/main.h000066400000000000000000000215171152373700300136170ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _MAIN_H_ #define _MAIN_H_ #include "list.h" #include "average.h" #define VERSION "3.0" #ifndef DO_DEBUG #define DO_DEBUG 0 #endif #define MAC_LEN 6 #define MAX_NODES 255 #define MAX_ESSIDS 255 #define MAX_BSSIDS 255 #define MAX_HISTORY 255 #define MAX_CHANNELS 64 #define MAX_ESSID_LEN 32 #define MAX_RATES 109 /* in 500kbps steps: 54 * 2 + 1 for array index */ #define MAX_FSTYPE 0xff #define MAX_FILTERMAC 9 /* packet types we actually care about, e.g filter */ #define PKT_TYPE_CTRL 0x000001 #define PKT_TYPE_MGMT 0x000002 #define PKT_TYPE_DATA 0x000004 #define PKT_TYPE_BEACON 0x000010 #define PKT_TYPE_PROBE 0x000020 #define PKT_TYPE_ASSOC 0x000040 #define PKT_TYPE_AUTH 0x000080 #define PKT_TYPE_RTS 0x000100 #define PKT_TYPE_CTS 0x000200 #define PKT_TYPE_ACK 0x000400 #define PKT_TYPE_NULL 0x000800 #define PKT_TYPE_ARP 0x001000 #define PKT_TYPE_IP 0x002000 #define PKT_TYPE_ICMP 0x004000 #define PKT_TYPE_UDP 0x008000 #define PKT_TYPE_TCP 0x010000 #define PKT_TYPE_OLSR 0x020000 #define PKT_TYPE_OLSR_LQ 0x040000 #define PKT_TYPE_OLSR_GW 0x080000 #define PKT_TYPE_BATMAN 0x100000 #define PKT_TYPE_MESHZ 0x200000 #define PKT_TYPE_ALL_MGMT (PKT_TYPE_BEACON | PKT_TYPE_PROBE | PKT_TYPE_ASSOC | PKT_TYPE_AUTH) #define PKT_TYPE_ALL_CTRL (PKT_TYPE_RTS | PKT_TYPE_CTS | PKT_TYPE_ACK) #define PKT_TYPE_ALL_DATA (PKT_TYPE_NULL | PKT_TYPE_ARP | PKT_TYPE_ICMP | PKT_TYPE_IP | \ PKT_TYPE_UDP | PKT_TYPE_TCP | PKT_TYPE_OLSR | PKT_TYPE_OLSR_LQ | \ PKT_TYPE_OLSR_GW | PKT_TYPE_BATMAN | PKT_TYPE_MESHZ) #define WLAN_MODE_AP 0x01 #define WLAN_MODE_IBSS 0x02 #define WLAN_MODE_STA 0x04 #define WLAN_MODE_PROBE 0x08 #define PHY_FLAG_SHORTPRE 0x0001 #define PHY_FLAG_BADFCS 0x0002 #define PHY_FLAG_A 0x0010 #define PHY_FLAG_B 0x0020 #define PHY_FLAG_G 0x0040 #define PHY_FLAG_MODE_MASK 0x00f0 /* default config values */ #define INTERFACE_NAME "wlan0" #define NODE_TIMEOUT 60 /* seconds */ #define CHANNEL_TIME 250000 /* 250 msec */ /* update display every 100ms - "10 frames per sec should be enough for everyone" ;) */ #define DISPLAY_UPDATE_INTERVAL 100000 /* usec */ #define RECV_BUFFER_SIZE 0 /* not used by default */ #define DEFAULT_PORT "4444" /* string because of getaddrinfo() */ #ifndef ARPHRD_IEEE80211_RADIOTAP #define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */ #endif #ifndef ARPHRD_IEEE80211_PRISM #define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header */ #endif struct packet_info { /* general */ unsigned int pkt_types; /* bitmask of packet types */ /* wlan phy (from radiotap) */ int phy_signal; /* signal strength (usually dBm) */ int phy_noise; /* noise level (usually dBm) */ unsigned int phy_snr; /* signal to noise ratio */ unsigned int phy_rate; /* physical rate */ unsigned int phy_freq; /* frequency from driver */ unsigned char phy_chan; /* channel from driver */ unsigned int phy_flags; /* A, B, G, shortpre */ /* wlan mac */ unsigned int wlan_len; /* packet length */ unsigned int wlan_type; /* frame control field */ unsigned char wlan_src[MAC_LEN]; unsigned char wlan_dst[MAC_LEN]; unsigned char wlan_bssid[MAC_LEN]; char wlan_essid[MAX_ESSID_LEN]; u_int64_t wlan_tsf; /* timestamp from beacon */ unsigned int wlan_bintval; /* beacon interval */ unsigned int wlan_mode; /* AP, STA or IBSS */ unsigned char wlan_channel; /* channel from beacon, probe */ unsigned char wlan_qos_class; /* for QDATA frames */ unsigned int wlan_nav; /* frame NAV duration */ unsigned int wlan_seqno; /* sequence number */ /* flags */ unsigned int wlan_wep:1, /* WEP on/off */ wlan_retry:1; /* IP */ unsigned int ip_src; unsigned int ip_dst; unsigned int tcpudp_port; unsigned int olsr_type; unsigned int olsr_neigh; unsigned int olsr_tc; /* calculated from other values */ unsigned int pkt_duration; /* packet "airtime" */ int pkt_chan_idx; /* received while on channel */ int wlan_retries; /* retry count for this frame */ }; struct essid_info; struct node_info { /* housekeeping */ struct list_head list; struct list_head essid_nodes; struct list_head on_channels; /* channels this node was seen on */ unsigned int num_on_channels; time_t last_seen; /* timestamp */ /* general packet info */ unsigned int pkt_types; /* bitmask of packet types we've seen */ unsigned int pkt_count; /* nr of packets seen */ /* wlan phy (from radiotap) */ int phy_snr_min; int phy_snr_max; struct ewma phy_snr_avg; int phy_sig_max; /* wlan mac */ unsigned char wlan_bssid[MAC_LEN]; unsigned int wlan_channel; /* channel from beacon, probe frames */ unsigned int wlan_mode; /* AP, STA or IBSS */ u_int64_t wlan_tsf; unsigned int wlan_bintval; unsigned int wlan_retries_all; unsigned int wlan_retries_last; unsigned int wlan_seqno; struct essid_info* essid; unsigned int wlan_wep:1; /* WEP active? */ /* IP */ unsigned int ip_src; /* IP address (if known) */ unsigned int olsr_count; /* number of OLSR packets */ unsigned int olsr_neigh; /* number if OLSR neighbours */ unsigned int olsr_tc; /* unused */ struct packet_info last_pkt; }; extern struct list_head nodes; struct essid_info { struct list_head list; char essid[MAX_ESSID_LEN]; struct list_head nodes; unsigned int num_nodes; int split; }; struct essid_meta_info { struct list_head list; struct essid_info* split_essid; int split_active; }; extern struct essid_meta_info essids; struct history { int signal[MAX_HISTORY]; int noise[MAX_HISTORY]; int rate[MAX_HISTORY]; unsigned int type[MAX_HISTORY]; unsigned int retry[MAX_HISTORY]; unsigned int index; }; extern struct history hist; struct statistics { unsigned long packets; unsigned long retries; unsigned long bytes; unsigned long duration; unsigned long packets_per_rate[MAX_RATES]; unsigned long bytes_per_rate[MAX_RATES]; unsigned long duration_per_rate[MAX_RATES]; unsigned long packets_per_type[MAX_FSTYPE]; unsigned long bytes_per_type[MAX_FSTYPE]; unsigned long duration_per_type[MAX_FSTYPE]; unsigned long filtered_packets; struct timeval stats_time; }; extern struct statistics stats; /* channel to frequency mapping */ struct chan_freq { int chan; int freq; }; extern struct chan_freq channels[MAX_CHANNELS]; struct channel_info { int signal; struct ewma signal_avg; int noise; unsigned long packets; unsigned long bytes; unsigned long durations; unsigned long durations_last; struct ewma durations_avg; struct list_head nodes; unsigned int num_nodes; }; extern struct channel_info spectrum[MAX_CHANNELS]; /* helper for keeping lists of nodes for each channel * (a node can be on more than one channel) */ struct chan_node { struct node_info* node; struct channel_info* chan; struct list_head chan_list; /* list for nodes per channel */ struct list_head node_list; /* list for channels per node */ int sig; struct ewma sig_avg; unsigned long packets; }; struct config { char* ifname; char* port; int quiet; int node_timeout; int channel_time; int channel_max; int current_channel; /* index into channels array */ int display_interval; char* dumpfile; int recv_buffer_size; char* serveraddr; unsigned char filtermac[MAX_FILTERMAC][MAC_LEN]; char filtermac_enabled[MAX_FILTERMAC]; unsigned char filterbssid[MAC_LEN]; int filter_pkt; unsigned int filter_off:1, do_change_channel:1, allow_client:1, /* this isn't exactly config, but wtf... */ do_macfilter:1, have_noise:1, display_initialized:1; int arphrd; // the device ARP type int paused; int num_channels; }; extern struct config conf; extern struct timeval the_time; #define CONF_CURRENT_CHANNEL (conf.current_channel >= 0 && conf.current_channel < MAX_CHANNELS ? \ channels[conf.current_channel].chan : 0) void free_lists(void); int change_channel(int idx); int find_channel_index(int c); void init_channels(void); void update_spectrum_durations(void); void handle_packet(struct packet_info* p); void __attribute__ ((format (printf, 1, 2))) printlog(const char *fmt, ...); #endif horst-3.0/network.c000066400000000000000000000327641152373700300143650ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include "main.h" #include "util.h" #include "network.h" extern struct config conf; int srv_fd = -1; int cli_fd = -1; static int netmon_fd; #define PROTO_VERSION 1 enum pkt_type { PROTO_PKT_INFO = 0, PROTO_CHAN_LIST = 1, PROTO_CONF_CHAN = 2, PROTO_CONF_FILTER = 3, }; struct net_header { unsigned char version; unsigned char type; } __attribute__ ((packed)); struct net_conf_chan { struct net_header proto; unsigned char do_change; unsigned char upper; char channel; int dwell_time; } __attribute__ ((packed)); struct net_conf_filter { struct net_header proto; unsigned char filtermac[MAX_FILTERMAC][MAC_LEN]; char filtermac_enabled[MAX_FILTERMAC]; unsigned char filterbssid[MAC_LEN]; int filter_pkt; unsigned char filter_off; } __attribute__ ((packed)); struct net_chan_list { struct net_header proto; unsigned char num_channels; struct { unsigned char chan; unsigned char freq; } channel[1]; } __attribute__ ((packed)); #define PKT_INFO_VERSION 1 struct net_packet_info { struct net_header proto; unsigned char version; /* general */ unsigned int pkt_types; /* bitmask of packet types */ /* wlan phy (from radiotap) */ int phy_signal; /* signal strength (usually dBm) */ int phy_noise; /* noise level (usually dBm) */ unsigned int phy_snr; /* signal to noise ratio */ unsigned int phy_rate; /* physical rate */ unsigned int phy_freq; /* frequency (unused) */ unsigned char phy_chan; /* channel from driver */ unsigned int phy_flags; /* A, B, G, shortpre */ /* wlan mac */ unsigned int wlan_len; /* packet length */ unsigned int wlan_type; /* frame control field */ unsigned char wlan_src[MAC_LEN]; unsigned char wlan_dst[MAC_LEN]; unsigned char wlan_bssid[MAC_LEN]; char wlan_essid[MAX_ESSID_LEN]; u_int64_t wlan_tsf; /* timestamp from beacon */ unsigned int wlan_bintval; /* beacon interval */ unsigned int wlan_mode; /* AP, STA or IBSS */ unsigned char wlan_channel; /* channel from beacon, probe */ unsigned char wlan_qos_class; /* for QDATA frames */ unsigned int wlan_nav; /* frame NAV duration */ unsigned int wlan_seqno; /* sequence number */ #define PKT_WLAN_FLAG_WEP 0x1 #define PKT_WLAN_FLAG_RETRY 0x2 /* bitfields are not portable - endianness is not guaranteed */ unsigned int wlan_flags; /* IP */ unsigned int ip_src; unsigned int ip_dst; unsigned int tcpudp_port; unsigned int olsr_type; unsigned int olsr_neigh; unsigned int olsr_tc; } __attribute__ ((packed)); static int net_write(int fd, unsigned char* buf, size_t len) { int ret; ret = write(fd, buf, len); if (ret == -1) { if (errno == EPIPE) { printlog("Client has closed"); close(fd); if (fd == cli_fd) cli_fd = -1; net_init_server_socket(conf.port); } else printlog("ERROR: in net_write"); return 0; } return 1; } int net_send_packet(struct packet_info *p) { struct net_packet_info np; np.proto.version = PROTO_VERSION; np.proto.type = PROTO_PKT_INFO; np.version = PKT_INFO_VERSION; np.pkt_types = htole32(p->pkt_types); np.phy_signal = htole32(p->phy_signal); np.phy_noise = htole32(p->phy_noise); np.phy_snr = htole32(p->phy_snr); np.phy_rate = htole32(p->phy_rate); np.phy_freq = htole32(p->phy_freq); np.phy_chan = p->phy_chan; np.phy_flags = htole32(p->phy_flags); np.wlan_len = htole32(p->wlan_len); np.wlan_type = htole32(p->wlan_type); memcpy(np.wlan_src, p->wlan_src, MAC_LEN); memcpy(np.wlan_dst, p->wlan_dst, MAC_LEN); memcpy(np.wlan_bssid, p->wlan_bssid, MAC_LEN); memcpy(np.wlan_essid, p->wlan_essid, MAX_ESSID_LEN); np.wlan_tsf = htole64(p->wlan_tsf); np.wlan_bintval = htole32(p->wlan_bintval); np.wlan_mode = htole32(p->wlan_mode); np.wlan_channel = p->wlan_channel; np.wlan_qos_class = p->wlan_qos_class; np.wlan_nav = htole32(p->wlan_nav); np.wlan_seqno = htole32(p->wlan_seqno); np.wlan_flags = 0; if (p->wlan_wep) np.wlan_flags |= PKT_WLAN_FLAG_WEP; if (p->wlan_retry) np.wlan_flags |= PKT_WLAN_FLAG_RETRY; np.wlan_flags = htole32(np.wlan_flags); np.ip_src = p->ip_src; np.ip_dst = p->ip_dst; np.tcpudp_port = htole32(p->tcpudp_port); np.olsr_type = htole32(p->olsr_type); np.olsr_neigh = htole32(p->olsr_neigh); np.olsr_tc = htole32(p->olsr_tc); net_write(cli_fd, (unsigned char *)&np, sizeof(np)); return 0; } static int net_receive_packet(unsigned char *buffer, int len) { struct net_packet_info *np; struct packet_info p; if (len < sizeof(struct net_packet_info)) return 0; np = (struct net_packet_info *)buffer; if (np->phy_rate == 0) return 0; if (np->version != PKT_INFO_VERSION) return 0; memset(&p, 0, sizeof(p)); p.pkt_types = le32toh(np->pkt_types); p.phy_signal = le32toh(np->phy_signal); p.phy_noise = le32toh(np->phy_noise); p.phy_snr = le32toh(np->phy_snr); p.phy_rate = le32toh(np->phy_rate); p.phy_freq = le32toh(np->phy_freq); p.phy_chan = np->phy_chan; p.phy_flags = le32toh(np->phy_flags); p.wlan_len = le32toh(np->wlan_len); p.wlan_type = le32toh(np->wlan_type); memcpy(p.wlan_src, np->wlan_src, MAC_LEN); memcpy(p.wlan_dst, np->wlan_dst, MAC_LEN); memcpy(p.wlan_bssid, np->wlan_bssid, MAC_LEN); memcpy(p.wlan_essid, np->wlan_essid, MAX_ESSID_LEN); p.wlan_tsf = le64toh(np->wlan_tsf); p.wlan_bintval = le32toh(np->wlan_bintval); p.wlan_mode = le32toh(np->wlan_mode); p.wlan_channel = np->wlan_channel; p.wlan_qos_class = np->wlan_qos_class; p.wlan_nav = le32toh(np->wlan_nav); p.wlan_seqno = le32toh(np->wlan_seqno); np->wlan_flags = le32toh(np->wlan_flags); if (np->wlan_flags & PKT_WLAN_FLAG_WEP) p.wlan_wep = 1; if (np->wlan_flags & PKT_WLAN_FLAG_RETRY) p.wlan_retry = 1; p.ip_src = np->ip_src; p.ip_dst = np->ip_dst; p.tcpudp_port = le32toh(np->tcpudp_port); p.olsr_type = le32toh(np->olsr_type); p.olsr_neigh = le32toh(np->olsr_neigh); p.olsr_tc = le32toh(np->olsr_tc); handle_packet(&p); return sizeof(struct net_packet_info); } void net_send_conf_chan(int fd) { struct net_conf_chan nc; nc.proto.version = PROTO_VERSION; nc.proto.type = PROTO_CONF_CHAN; nc.do_change = conf.do_change_channel; nc.upper = conf.channel_max; nc.channel = conf.current_channel; nc.dwell_time = htole32(conf.channel_time); net_write(fd, (unsigned char *)&nc, sizeof(nc)); } static int net_receive_conf_chan(unsigned char *buffer, int len) { struct net_conf_chan *nc; if (len < sizeof(struct net_conf_chan)) return 0; nc = (struct net_conf_chan *)buffer; conf.do_change_channel = nc->do_change; conf.channel_max = nc->upper; conf.channel_time = le32toh(nc->dwell_time); if (cli_fd > -1 && nc->channel != conf.current_channel) /* server */ change_channel(nc->channel); else { /* client */ conf.current_channel = nc->channel; update_spectrum_durations(); } return sizeof(struct net_conf_chan); } int net_send_conf_filter(int fd) { struct net_conf_filter nc; int i; nc.proto.version = PROTO_VERSION; nc.proto.type = PROTO_CONF_FILTER; for (i = 0; i < MAX_FILTERMAC; i++) { memcpy(nc.filtermac[i], conf.filtermac[i], MAC_LEN); nc.filtermac_enabled[i] = conf.filtermac_enabled[i]; } memcpy(nc.filterbssid, conf.filterbssid, MAC_LEN); nc.filter_pkt = htole32(conf.filter_pkt); nc.filter_off = conf.filter_off; net_write(fd, (unsigned char *)&nc, sizeof(nc)); return 0; } static int net_receive_conf_filter(unsigned char *buffer, int len) { struct net_conf_filter *nc; int i; if (len < sizeof(struct net_conf_filter)) return 0; nc = (struct net_conf_filter *)buffer; for (i = 0; i < MAX_FILTERMAC; i++) { memcpy(conf.filtermac[i], nc->filtermac[i], MAC_LEN); conf.filtermac_enabled[i] = nc->filtermac_enabled[i]; } memcpy(conf.filterbssid, nc->filterbssid, MAC_LEN); conf.filter_pkt = le32toh(nc->filter_pkt); conf.filter_off = nc->filter_off; return sizeof(struct net_conf_filter); } static int net_send_chan_list(int fd) { char* buf; struct net_chan_list *nc; int i; buf = malloc(sizeof(struct net_chan_list) + 2*(conf.num_channels - 1)); if (buf == NULL) return 0; nc = (struct net_chan_list *)buf; nc->proto.version = PROTO_VERSION; nc->proto.type = PROTO_CHAN_LIST; for (i = 0; i < conf.num_channels && i < MAX_CHANNELS; i++) { nc->channel[i].chan = channels[i].chan; nc->channel[i].freq = channels[i].freq; } nc->num_channels = i; net_write(fd, (unsigned char *)buf, sizeof(struct net_chan_list) + 2*(i - 1)); free(buf); return 0; } static int net_receive_chan_list(unsigned char *buffer, int len) { struct net_chan_list *nc; int i; if (len < sizeof(struct net_chan_list)) return 0; nc = (struct net_chan_list *)buffer; if (len < sizeof(struct net_chan_list) + 2*(nc->num_channels - 1)) return 0; for (i = 0; i < nc->num_channels && i < MAX_CHANNELS; i++) { channels[i].chan = nc->channel[i].chan; channels[i].freq = nc->channel[i].freq; } conf.num_channels = i; init_channels(); return sizeof(struct net_chan_list) + 2*(nc->num_channels - 1); } int try_receive_packet(unsigned char* buf, int len) { struct net_header *nh = (struct net_header *)buf; if (nh->version != PROTO_VERSION) { printlog("ERROR: protocol version %x", nh->version); return 0; } switch (nh->type) { case PROTO_PKT_INFO: len = net_receive_packet(buf, len); break; case PROTO_CHAN_LIST: len = net_receive_chan_list(buf, len); break; case PROTO_CONF_CHAN: len = net_receive_conf_chan(buf, len); break; case PROTO_CONF_FILTER: len = net_receive_conf_filter(buf, len); break; default: printlog("ERROR: unknown net packet type"); len = 0; } return len; /* the number of bytes we have consumed */ } int net_receive(int fd, unsigned char* buffer, size_t* buflen, size_t maxlen) { int len, consumed = 0; len = recv(fd, buffer + *buflen, maxlen - *buflen, MSG_DONTWAIT); if (len < 0) return 0; *buflen += len; while (*buflen > sizeof(struct net_header)) { len = try_receive_packet(buffer + consumed, *buflen); if (len == 0) break; *buflen -= len; consumed += len; } memmove(buffer, buffer + consumed, *buflen); return consumed; } int net_handle_server_conn( void ) { struct sockaddr_in cin; socklen_t cinlen; cinlen = sizeof(cin); memset(&cin, 0, sizeof(struct sockaddr_in)); cli_fd = accept(srv_fd, (struct sockaddr*)&cin, &cinlen); printlog("Accepting client"); /* send initial config */ net_send_chan_list(cli_fd); net_send_conf_chan(cli_fd); net_send_conf_filter(cli_fd); /* we only accept one client, so close server socket */ close(srv_fd); srv_fd = -1; return 0; } void net_init_server_socket(char* rport) { struct sockaddr_in sock_in; int reuse = 1; printlog("Initializing server port %s", rport); memset(&sock_in, 0, sizeof(struct sockaddr_in)); sock_in.sin_family = AF_INET; sock_in.sin_addr.s_addr = htonl(INADDR_ANY); sock_in.sin_port = htons(atoi(rport)); if ((srv_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) err(1, "Could not open server socket"); if (setsockopt(srv_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) err(1, "setsockopt SO_REUSEADDR"); if (bind(srv_fd, (struct sockaddr*)&sock_in, sizeof(sock_in)) < 0) err(1, "bind"); if (listen(srv_fd, 0) < 0) err(1, "listen"); } int net_open_client_socket(char* serveraddr, char* rport) { struct addrinfo saddr; struct addrinfo *result, *rp; int ret; printlog("Connecting to server %s port %s", serveraddr, rport); /* Obtain address(es) matching host/port */ memset(&saddr, 0, sizeof(struct addrinfo)); saddr.ai_family = AF_INET; saddr.ai_socktype = SOCK_STREAM; saddr.ai_flags = 0; saddr.ai_protocol = 0; ret = getaddrinfo(serveraddr, rport, &saddr, &result); if (ret != 0) { fprintf(stderr, "Could not resolve: %s\n", gai_strerror(ret)); exit(EXIT_FAILURE); } /* getaddrinfo() returns a list of address structures. * Try each address until we successfully connect. */ for (rp = result; rp != NULL; rp = rp->ai_next) { netmon_fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (netmon_fd == -1) continue; if (connect(netmon_fd, rp->ai_addr, rp->ai_addrlen) != -1) break; /* Success */ close(netmon_fd); } if (rp == NULL) { /* No address succeeded */ freeaddrinfo(result); err(1, "Could not connect"); } freeaddrinfo(result); printlog("Connected to server %s", serveraddr); return netmon_fd; } void net_finish(void) { if (srv_fd != -1) close(srv_fd); if (cli_fd != -1) close(cli_fd); if (netmon_fd) close(netmon_fd); } void net_send_channel_config(void) { if (conf.serveraddr) net_send_conf_chan(netmon_fd); else if (conf.allow_client && cli_fd > -1) net_send_conf_chan(cli_fd); } void net_send_filter_config(void) { if (conf.serveraddr) net_send_conf_filter(netmon_fd); else if (conf.allow_client && cli_fd > -1) net_send_conf_filter(cli_fd); } horst-3.0/network.h000066400000000000000000000024511152373700300143600ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _PROTOCOL_NETWORK_H_ #define _PROTOCOL_NETWORK_H_ struct packet_info; extern int srv_fd; extern int cli_fd; void net_init_server_socket(char* rport); int net_handle_server_conn(void); int net_send_packet(struct packet_info *pkt); void net_send_channel_config(void); void net_send_filter_config(void); int net_receive(int fd, unsigned char* buffer, size_t* buflen, size_t maxlen); int net_open_client_socket(char* server, char* rport); void net_finish(void); #endif horst-3.0/node.c000066400000000000000000000076301152373700300136130ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include "main.h" #include "util.h" #include "ieee80211.h" static struct timeval last_nodetimeout; void remove_node_from_essid(struct node_info* n); static void copy_nodeinfo(struct node_info* n, struct packet_info* p) { memcpy(&(n->last_pkt), p, sizeof(struct packet_info)); // update timestamp n->last_seen = time(NULL); n->pkt_count++; n->pkt_types |= p->pkt_types; if (p->ip_src) n->ip_src = p->ip_src; if (p->wlan_mode) n->wlan_mode = p->wlan_mode; if (p->olsr_tc) n->olsr_tc = p->olsr_tc; if (p->olsr_neigh) n->olsr_neigh = p->olsr_neigh; if (p->pkt_types & PKT_TYPE_OLSR) n->olsr_count++; if (p->wlan_bssid[0] != 0xff && !(p->wlan_bssid[0] == 0 && p->wlan_bssid[1] == 0 && p->wlan_bssid[2] == 0 && p->wlan_bssid[3] == 0 && p->wlan_bssid[4] == 0 && p->wlan_bssid[5] == 0)) { memcpy(n->wlan_bssid, p->wlan_bssid, MAC_LEN); } if (IEEE80211_IS_MGMT_STYPE(p->wlan_type, IEEE80211_STYPE_BEACON)) { n->wlan_tsf = p->wlan_tsf; n->wlan_bintval = p->wlan_bintval; } ewma_add(&n->phy_snr_avg, p->phy_snr); if (p->phy_snr > n->phy_snr_max) n->phy_snr_max = p->phy_snr; if (p->phy_signal > n->phy_sig_max || n->phy_sig_max == 0) n->phy_sig_max = p->phy_signal; if ((n->phy_snr_min == 0 && p->phy_snr > 0) || p->phy_snr < n->phy_snr_min) n->phy_snr_min = p->phy_snr; if (p->wlan_channel != 0) n->wlan_channel = p->wlan_channel; else if (p->pkt_chan_idx >= 0) n->wlan_channel = channels[p->pkt_chan_idx].chan; if (!IEEE80211_IS_CTRL(p->wlan_type)) n->wlan_wep = p->wlan_wep; if (p->wlan_seqno != 0) { if (p->wlan_retry && p->wlan_seqno == n->wlan_seqno) { n->wlan_retries_all++; n->wlan_retries_last++; } else n->wlan_retries_last = 0; n->wlan_seqno = p->wlan_seqno; } } struct node_info* node_update(struct packet_info* p) { struct node_info* n; if (p->wlan_src[0] == 0 && p->wlan_src[1] == 0 && p->wlan_src[2] == 0 && p->wlan_src[3] == 0 && p->wlan_src[4] == 0 && p->wlan_src[5] == 0) return NULL; /* find node by wlan source address */ list_for_each_entry(n, &nodes, list) { if (memcmp(p->wlan_src, n->last_pkt.wlan_src, MAC_LEN) == 0) { DEBUG("node found %p\n", n); break; } } /* not found */ if (&n->list == &nodes) { DEBUG("node adding\n"); n = malloc(sizeof(struct node_info)); memset(n, 0, sizeof(struct node_info)); n->essid = NULL; ewma_init(&n->phy_snr_avg, 1024, 8); INIT_LIST_HEAD(&n->on_channels); list_add_tail(&n->list, &nodes); } copy_nodeinfo(n, p); return n; } void timeout_nodes(void) { struct node_info *n, *m; struct chan_node *cn, *cn2; if ((the_time.tv_sec - last_nodetimeout.tv_sec) < conf.node_timeout ) return; list_for_each_entry_safe(n, m, &nodes, list) { if (n->last_seen < (the_time.tv_sec - conf.node_timeout)) { list_del(&n->list); if (n->essid != NULL) remove_node_from_essid(n); list_for_each_entry_safe(cn, cn2, &n->on_channels, node_list) { list_del(&cn->node_list); list_del(&cn->chan_list); cn->chan->num_nodes--; free(cn); } free(n); } } last_nodetimeout = the_time; } horst-3.0/olsr_header.h000066400000000000000000000123401152373700300151540ustar00rootroot00000000000000/* copied from olsr olsr_protocol.h */ /* * The olsr.org Optimized Link-State Routing daemon(olsrd) * Copyright (c) 2004, Andreas T�nnesen(andreto@olsr.org) * 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 olsr.org, olsrd 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. * * Visit http://www.olsr.org for more information. * * If you find this software useful feel free to make a donation * to the project. For more information see the website or contact * the copyright holders. * * $Id: olsr_protocol.h,v 1.23 2007/11/08 22:47:41 bernd67 Exp $ */ #ifndef _OLSR_HEADER_H_ #define _OLSR_HEADER_H_ #include #include typedef u_int8_t olsr_u8_t; typedef u_int16_t olsr_u16_t; typedef u_int32_t olsr_u32_t; /* from olsr olsr_protocol.h */ /*********************************************** * OLSR packet definitions * ***********************************************/ /* *Hello info */ struct hellinfo { olsr_u8_t link_code; olsr_u8_t reserved; olsr_u16_t size; olsr_u32_t neigh_addr[1]; /* neighbor IP address(es) */ } __attribute__ ((packed)); struct hellomsg { olsr_u16_t reserved; olsr_u8_t htime; olsr_u8_t willingness; struct hellinfo hell_info[1]; } __attribute__ ((packed)); /* * Topology Control packet */ struct neigh_info { olsr_u32_t addr; } __attribute__ ((packed)); struct tcmsg { olsr_u16_t ansn; olsr_u16_t reserved; struct neigh_info neigh[1]; } __attribute__ ((packed)); /* *Multiple Interface Declaration message */ /* * Defined as s struct for further expansion * For example: do we want to tell what type of interface * is associated whit each address? */ struct midaddr { olsr_u32_t addr; } __attribute__ ((packed)); struct midmsg { struct midaddr mid_addr[1]; } __attribute__ ((packed)); /* * Host and Network Association message */ struct hnapair { olsr_u32_t addr; olsr_u32_t netmask; } __attribute__ ((packed)); struct hnamsg { struct hnapair hna_net[1]; } __attribute__ ((packed)); /* * OLSR message (several can exist in one OLSR packet) */ struct olsrmsg { olsr_u8_t olsr_msgtype; olsr_u8_t olsr_vtime; olsr_u16_t olsr_msgsize; olsr_u32_t originator; olsr_u8_t ttl; olsr_u8_t hopcnt; olsr_u16_t seqno; union { struct hellomsg hello; struct tcmsg tc; struct hnamsg hna; struct midmsg mid; } message; } __attribute__ ((packed)); /* * Generic OLSR packet */ struct olsr { olsr_u16_t olsr_packlen; /* packet length */ olsr_u16_t olsr_seqno; struct olsrmsg olsr_msg[1]; /* variable messages */ } __attribute__ ((packed)); /* *Message Types */ #define HELLO_MESSAGE 1 #define TC_MESSAGE 2 #define MID_MESSAGE 3 #define HNA_MESSAGE 4 #define LQ_HELLO_MESSAGE 201 #define LQ_TC_MESSAGE 202 /* *Link Types */ #define UNSPEC_LINK 0 #define ASYM_LINK 1 #define SYM_LINK 2 #define LOST_LINK 3 #define HIDE_LINK 4 #define MAX_LINK 4 /* *Neighbor Types */ #define NOT_NEIGH 0 #define SYM_NEIGH 1 #define MPR_NEIGH 2 #define MAX_NEIGH 2 /* *Neighbor status */ #define NOT_SYM 0 #define SYM 1 // serialized IPv4 OLSR header struct olsr_header_v4 { olsr_u8_t type; olsr_u8_t vtime; olsr_u16_t size; olsr_u32_t orig; olsr_u8_t ttl; olsr_u8_t hops; olsr_u16_t seqno; }; // serialized LQ_HELLO struct lq_hello_info_header { olsr_u8_t link_code; olsr_u8_t reserved; olsr_u16_t size; }; struct lq_hello_header { olsr_u16_t reserved; olsr_u8_t htime; olsr_u8_t will; }; // serialized LQ_TC struct lq_tc_header { olsr_u16_t ansn; olsr_u16_t reserved; }; #endif horst-3.0/prism_header.h000066400000000000000000000057541152373700300153420ustar00rootroot00000000000000/* copied from madwifi net80211/ieee80211_monitor.h */ /*- * Copyright (c) 2005 John Bicket * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. * * $Id: ieee80211_monitor.h 2568 2007-07-09 13:37:26Z proski $ */ #ifndef _PRISM_HEADER_H_ #define _PRISM_HEADER_H_ #include enum { DIDmsg_lnxind_wlansniffrm = 0x00000044, DIDmsg_lnxind_wlansniffrm_hosttime = 0x00010044, DIDmsg_lnxind_wlansniffrm_mactime = 0x00020044, DIDmsg_lnxind_wlansniffrm_channel = 0x00030044, DIDmsg_lnxind_wlansniffrm_rssi = 0x00040044, DIDmsg_lnxind_wlansniffrm_sq = 0x00050044, DIDmsg_lnxind_wlansniffrm_signal = 0x00060044, DIDmsg_lnxind_wlansniffrm_noise = 0x00070044, DIDmsg_lnxind_wlansniffrm_rate = 0x00080044, DIDmsg_lnxind_wlansniffrm_istx = 0x00090044, DIDmsg_lnxind_wlansniffrm_frmlen = 0x000A0044 }; enum { P80211ENUM_msgitem_status_no_value = 0x00 }; enum { P80211ENUM_truth_false = 0x00, P80211ENUM_truth_true = 0x01 }; typedef struct { u_int32_t did; u_int16_t status; u_int16_t len; u_int32_t data; } p80211item_uint32_t; typedef struct { u_int32_t msgcode; u_int32_t msglen; #define WLAN_DEVNAMELEN_MAX 16 u_int8_t devname[WLAN_DEVNAMELEN_MAX]; p80211item_uint32_t hosttime; p80211item_uint32_t mactime; p80211item_uint32_t channel; p80211item_uint32_t rssi; p80211item_uint32_t sq; p80211item_uint32_t signal; p80211item_uint32_t noise; p80211item_uint32_t rate; p80211item_uint32_t istx; p80211item_uint32_t frmlen; } wlan_ng_prism2_header; #define PRISM_HEADER_LEN sizeof(wlan_ng_prism2_header) #endif horst-3.0/protocol_parser.c000066400000000000000000000441441152373700300161040ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "prism_header.h" #include "ieee80211_radiotap.h" #include "ieee80211.h" #include "ieee80211_util.h" #include "olsr_header.h" #include "batman_header.h" #include "protocol_parser.h" #include "main.h" #include "util.h" static int parse_prism_header(unsigned char** buf, int len, struct packet_info* p); static int parse_radiotap_header(unsigned char** buf, int len, struct packet_info* p); static int parse_80211_header(unsigned char** buf, int len, struct packet_info* p); static int parse_llc(unsigned char** buf, int len, struct packet_info* p); static int parse_ip_header(unsigned char** buf, int len, struct packet_info* p); static int parse_udp_header(unsigned char** buf, int len, struct packet_info* p); static int parse_olsr_packet(unsigned char** buf, int len, struct packet_info* p); static int parse_batman_packet(unsigned char** buf, int len, struct packet_info* p); static int parse_meshcruzer_packet(unsigned char** buf, int len, struct packet_info* p, int port); /* return 1 if we parsed enough = min ieee header */ int parse_packet(unsigned char* buf, int len, struct packet_info* p) { if (conf.arphrd == ARPHRD_IEEE80211_PRISM) { len = parse_prism_header(&buf, len, p); if (len <= 0) return 0; } else if (conf.arphrd == ARPHRD_IEEE80211_RADIOTAP) { len = parse_radiotap_header(&buf, len, p); if (len <= 0) return 0; } if (conf.arphrd == ARPHRD_IEEE80211 || conf.arphrd == ARPHRD_IEEE80211_PRISM || conf.arphrd == ARPHRD_IEEE80211_RADIOTAP) { DEBUG("before parse 80211 len: %d\n", len); len = parse_80211_header(&buf, len, p); if (len < 0) /* couldnt parse */ return 0; else if (len == 0) return 1; } len = parse_llc(&buf, len, p); if (len <= 0) return 1; len = parse_ip_header(&buf, len, p); if (len <= 0) return 1; len = parse_udp_header(&buf, len, p); if (len <= 0) return 1; return 1; } static int parse_prism_header(unsigned char** buf, int len, struct packet_info* p) { wlan_ng_prism2_header* ph; DEBUG("PRISM2 HEADER\n"); if (len < sizeof(wlan_ng_prism2_header)) return -1; ph = (wlan_ng_prism2_header*)*buf; /* * different drivers report S/N and rssi values differently * let's make sure here that SNR is always positive, so we * don't have do handle special cases later */ if (((int)ph->noise.data) < 0) { /* new madwifi */ p->phy_signal = ph->signal.data; p->phy_noise = ph->noise.data; p->phy_snr = ph->rssi.data; } else if (((int)ph->rssi.data) < 0) { /* broadcom hack */ p->phy_signal = ph->rssi.data; p->phy_noise = -95; p->phy_snr = 95 + ph->rssi.data; } else { /* assume hostap */ p->phy_signal = ph->signal.data; p->phy_noise = ph->noise.data; p->phy_snr = ph->signal.data - ph->noise.data; //XXX rssi? } p->phy_rate = ph->rate.data; /* just in case...*/ if (p->phy_snr < 0) p->phy_snr = -p->phy_snr; if (p->phy_snr > 99) p->phy_snr = 99; if (p->phy_rate == 0 || p->phy_rate > 108) { /* assume min rate, guess mode from channel */ DEBUG("*** fixing wrong rate\n"); if (ph->channel.data > 14) p->phy_rate = 12; /* 6 * 2 */ else p->phy_rate = 2; /* 1 * 2 */ } /* guess phy mode */ if (ph->channel.data > 14) p->phy_flags |= PHY_FLAG_A; else p->phy_flags |= PHY_FLAG_G; /* always assume shortpre */ p->phy_flags |= PHY_FLAG_SHORTPRE; DEBUG("devname: %s\n", ph->devname); DEBUG("signal: %d -> %d\n", ph->signal.data, p->phy_signal); DEBUG("noise: %d -> %d\n", ph->noise.data, p->phy_noise); DEBUG("rate: %d\n", ph->rate.data); DEBUG("rssi: %d\n", ph->rssi.data); DEBUG("*** SNR %d\n", p->phy_snr); *buf = *buf + sizeof(wlan_ng_prism2_header); return len - sizeof(wlan_ng_prism2_header); } static int parse_radiotap_header(unsigned char** buf, int len, struct packet_info* p) { struct ieee80211_radiotap_header* rh; __le32 present; /* the present bitmap */ unsigned char* b; /* current byte */ int i; u16 rt_len, x; DEBUG("RADIOTAP HEADER\n"); DEBUG("len: %d\n", len); if (len < sizeof(struct ieee80211_radiotap_header)) return -1; rh = (struct ieee80211_radiotap_header*)*buf; b = *buf + sizeof(struct ieee80211_radiotap_header); present = le32toh(rh->it_present); rt_len = le16toh(rh->it_len); DEBUG("radiotap header len: %d\n", rt_len); DEBUG("%08x\n", present); /* check for header extension - ignore for now, just advance current position */ while (present & 0x80000000 && b - *buf < rt_len) { DEBUG("extension\n"); b = b + 4; present = le32toh(*(__le32*)b); } present = le32toh(rh->it_present); // in case it moved /* radiotap bitmap has 32 bit, but we are only interrested until * bit 12 (IEEE80211_RADIOTAP_DB_ANTSIGNAL) => i<13 */ for (i = 0; i < 13 && b - *buf < rt_len; i++) { if ((present >> i) & 1) { DEBUG("1"); switch (i) { /* just ignore the following (advance position only) */ case IEEE80211_RADIOTAP_TSFT: DEBUG("[+8]"); b = b + 8; break; case IEEE80211_RADIOTAP_DBM_TX_POWER: case IEEE80211_RADIOTAP_ANTENNA: case IEEE80211_RADIOTAP_RTS_RETRIES: case IEEE80211_RADIOTAP_DATA_RETRIES: DEBUG("[+1]"); b++; break; case IEEE80211_RADIOTAP_EXT: DEBUG("[+4]"); b = b + 4; break; case IEEE80211_RADIOTAP_FHSS: case IEEE80211_RADIOTAP_LOCK_QUALITY: case IEEE80211_RADIOTAP_TX_ATTENUATION: case IEEE80211_RADIOTAP_RX_FLAGS: case IEEE80211_RADIOTAP_TX_FLAGS: case IEEE80211_RADIOTAP_DB_TX_ATTENUATION: DEBUG("[+2]"); b = b + 2; break; /* we are only interrested in these: */ case IEEE80211_RADIOTAP_RATE: DEBUG("[rate %0x]", *b); p->phy_rate = (*b); b++; break; case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: DEBUG("[sig %0x]", *b); p->phy_signal = *(char*)b; b++; break; case IEEE80211_RADIOTAP_DBM_ANTNOISE: DEBUG("[noi %0x]", *b); p->phy_noise = *(char*)b; b++; break; case IEEE80211_RADIOTAP_DB_ANTSIGNAL: DEBUG("[snr %0x]", *b); p->phy_snr = *b; b++; break; case IEEE80211_RADIOTAP_FLAGS: /* short preamble */ DEBUG("[flags %0x", *b); if (*b & IEEE80211_RADIOTAP_F_SHORTPRE) { p->phy_flags |= PHY_FLAG_SHORTPRE; DEBUG(" shortpre"); } if (*b & IEEE80211_RADIOTAP_F_BADFCS) { p->phy_flags |= PHY_FLAG_BADFCS; DEBUG(" badfcs"); } DEBUG("]"); b++; break; case IEEE80211_RADIOTAP_CHANNEL: /* channel & channel type */ p->phy_freq = le16toh(*(u_int16_t*)b); p->phy_chan = ieee80211_frequency_to_channel(p->phy_freq); DEBUG("[freq %d chan %d", p->phy_freq, p->phy_chan); b = b + 2; x = le16toh(*(u_int16_t*)b); if (x & IEEE80211_CHAN_A) { p->phy_flags |= PHY_FLAG_A; DEBUG("A]"); } else if (x & IEEE80211_CHAN_G) { p->phy_flags |= PHY_FLAG_G; DEBUG("G]"); } else if (x & IEEE80211_CHAN_B) { p->phy_flags |= PHY_FLAG_B; DEBUG("B]"); } b = b + 2; break; } } else { DEBUG("0"); } } DEBUG("\n"); if (!(present & (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL))) { /* no SNR in radiotap, try to calculate */ if (present & (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) && present & (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) && p->phy_noise < 0) p->phy_snr = p->phy_signal - p->phy_noise; /* HACK: here we just assume noise to be -95dBm */ else { p->phy_snr = p->phy_signal + 95; //simulate noise: p->phy_noise = -90; } } /* sanitize */ if (p->phy_snr > 99) p->phy_snr = 99; if (p->phy_rate == 0 || p->phy_rate > 108) { /* assume min rate for mode */ DEBUG("*** fixing wrong rate\n"); if (p->phy_flags & PHY_FLAG_A) p->phy_rate = 12; /* 6 * 2 */ else if (p->phy_flags & PHY_FLAG_B) p->phy_rate = 2; /* 1 * 2 */ else if (p->phy_flags & PHY_FLAG_G) p->phy_rate = 12; /* 6 * 2 */ else p->phy_rate = 2; } DEBUG("\nrate: %d\n", p->phy_rate); DEBUG("signal: %d\n", p->phy_signal); DEBUG("noise: %d\n", p->phy_noise); DEBUG("snr: %d\n", p->phy_snr); *buf = *buf + rt_len; return len - rt_len; } static int parse_80211_header(unsigned char** buf, int len, struct packet_info* p) { struct ieee80211_hdr* wh; struct ieee80211_mgmt* whm; int hdrlen; u8* sa = NULL; u8* da = NULL; u8* bssid = NULL; u16 fc, cap_i; if (len < 2) /* not even enough space for fc */ return -1; wh = (struct ieee80211_hdr*)*buf; fc = le16toh(wh->frame_control); hdrlen = ieee80211_get_hdrlen(fc); DEBUG("len %d hdrlen %d\n", len, hdrlen); if (len < hdrlen) return -1; p->wlan_len = len; p->wlan_type = (fc & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)); DEBUG("wlan_type %x - type %x - stype %x\n", fc, fc & IEEE80211_FCTL_FTYPE, fc & IEEE80211_FCTL_STYPE ); DEBUG("%s\n", get_packet_type_name(fc)); bssid = ieee80211_get_bssid(wh, len); switch (p->wlan_type & IEEE80211_FCTL_FTYPE) { case IEEE80211_FTYPE_DATA: p->pkt_types = PKT_TYPE_DATA; switch (p->wlan_type & IEEE80211_FCTL_STYPE) { case IEEE80211_STYPE_NULLFUNC: p->pkt_types |= PKT_TYPE_NULL; break; case IEEE80211_STYPE_QOS_DATA: /* TODO: ouch, should properly define a qos header */ p->wlan_qos_class = wh->addr4[0] & 0x7; DEBUG("***QDATA %x\n", p->wlan_qos_class); break; } p->wlan_nav = le16toh(wh->duration_id); DEBUG("DATA NAV %d\n", p->wlan_nav); p->wlan_seqno = le16toh(wh->seq_ctrl); DEBUG("DATA SEQ %d\n", p->wlan_seqno); sa = ieee80211_get_SA(wh); da = ieee80211_get_DA(wh); /* AP, STA or IBSS */ if ((fc & IEEE80211_FCTL_FROMDS) == 0 && (fc & IEEE80211_FCTL_TODS) == 0) p->wlan_mode = WLAN_MODE_IBSS; else if (fc & IEEE80211_FCTL_FROMDS) p->wlan_mode = WLAN_MODE_AP; else if (fc & IEEE80211_FCTL_TODS) p->wlan_mode = WLAN_MODE_STA; /* WEP */ if (fc & IEEE80211_FCTL_PROTECTED) p->wlan_wep = 1; if (fc & IEEE80211_FCTL_RETRY) p->wlan_retry = 1; break; case IEEE80211_FTYPE_CTL: p->pkt_types = PKT_TYPE_CTRL; switch (p->wlan_type & IEEE80211_FCTL_STYPE) { case IEEE80211_STYPE_RTS: p->pkt_types |= PKT_TYPE_RTS; p->wlan_nav = le16toh(wh->duration_id); DEBUG("RTS NAV %d\n", p->wlan_nav); sa = wh->addr2; da = wh->addr1; break; case IEEE80211_STYPE_CTS: p->pkt_types |= PKT_TYPE_CTS; p->wlan_nav = le16toh(wh->duration_id); DEBUG("CTS NAV %d\n", p->wlan_nav); da = wh->addr1; break; case IEEE80211_STYPE_ACK: p->pkt_types |= PKT_TYPE_ACK; p->wlan_nav = le16toh(wh->duration_id); DEBUG("ACK NAV %d\n", p->wlan_nav); da = wh->addr1; break; case IEEE80211_STYPE_PSPOLL: sa = wh->addr2; break; case IEEE80211_STYPE_CFEND: da = wh->addr1; sa = wh->addr2; break; case IEEE80211_STYPE_CFENDACK: /* dont know, dont care */ break; } break; case IEEE80211_FTYPE_MGMT: p->pkt_types = PKT_TYPE_MGMT; whm = (struct ieee80211_mgmt*)*buf; sa = whm->sa; da = whm->da; p->wlan_seqno = le16toh(wh->seq_ctrl); DEBUG("MGMT SEQ %d\n", p->wlan_seqno); if (fc & IEEE80211_FCTL_RETRY) p->wlan_retry = 1; switch (p->wlan_type & IEEE80211_FCTL_STYPE) { case IEEE80211_STYPE_BEACON: p->pkt_types |= PKT_TYPE_BEACON; p->wlan_tsf = le64toh(whm->u.beacon.timestamp); p->wlan_bintval = le16toh(whm->u.beacon.beacon_int); ieee802_11_parse_elems(whm->u.beacon.variable, len - sizeof(struct ieee80211_mgmt) - 4 /* FCS */, p); DEBUG("ESSID %s \n", p->wlan_essid ); DEBUG("CHAN %d \n", p->wlan_channel ); cap_i = le16toh(whm->u.beacon.capab_info); if (cap_i & WLAN_CAPABILITY_IBSS) p->wlan_mode = WLAN_MODE_IBSS; else if (cap_i & WLAN_CAPABILITY_ESS) p->wlan_mode = WLAN_MODE_AP; if (cap_i & WLAN_CAPABILITY_PRIVACY) p->wlan_wep = 1; break; case IEEE80211_STYPE_PROBE_RESP: p->pkt_types |= PKT_TYPE_PROBE; p->wlan_tsf = le64toh(whm->u.beacon.timestamp); ieee802_11_parse_elems(whm->u.beacon.variable, len - sizeof(struct ieee80211_mgmt) - 4 /* FCS */, p); DEBUG("ESSID %s \n", p->wlan_essid ); DEBUG("CHAN %d \n", p->wlan_channel ); cap_i = le16toh(whm->u.beacon.capab_info); if (cap_i & WLAN_CAPABILITY_IBSS) p->wlan_mode = WLAN_MODE_IBSS; else if (cap_i & WLAN_CAPABILITY_ESS) p->wlan_mode = WLAN_MODE_AP; if (cap_i & WLAN_CAPABILITY_PRIVACY) p->wlan_wep = 1; break; case IEEE80211_STYPE_PROBE_REQ: p->pkt_types |= PKT_TYPE_PROBE; ieee802_11_parse_elems(whm->u.probe_req.variable, len - 24 - 4 /* FCS */, p); p->wlan_mode |= WLAN_MODE_PROBE; break; case IEEE80211_STYPE_ASSOC_REQ: case IEEE80211_STYPE_ASSOC_RESP: case IEEE80211_STYPE_REASSOC_REQ: case IEEE80211_STYPE_REASSOC_RESP: case IEEE80211_STYPE_DISASSOC: p->pkt_types |= PKT_TYPE_ASSOC; break; case IEEE80211_STYPE_AUTH: case IEEE80211_STYPE_DEAUTH: p->pkt_types |= PKT_TYPE_AUTH; break; } break; } if (sa != NULL) { memcpy(p->wlan_src, sa, MAC_LEN); DEBUG("SA %s\n", ether_sprintf(sa)); } if (da != NULL) { memcpy(p->wlan_dst, da, MAC_LEN); DEBUG("DA %s\n", ether_sprintf(da)); } if (bssid!=NULL) { memcpy(p->wlan_bssid, bssid, MAC_LEN); DEBUG("BSSID %s\n", ether_sprintf(bssid)); } /* only data frames contain more info, otherwise stop parsing */ if (IEEE80211_IS_DATA(p->wlan_type) && p->wlan_wep != 1) { *buf = *buf + hdrlen; return len - hdrlen; } return 0; } static int parse_llc(unsigned char ** buf, int len, struct packet_info* p) { DEBUG("* parse LLC\n"); if (len < 6) return -1; /* check type in LLC header */ *buf = *buf + 6; if (**buf != 0x08) return -1; (*buf)++; if (**buf == 0x06) { /* ARP */ p->pkt_types |= PKT_TYPE_ARP; return 0; } if (**buf != 0x00) /* not IP */ return -1; (*buf)++; DEBUG("* parse LLC left %d\n", len - 8); return len - 8; } static int parse_ip_header(unsigned char** buf, int len, struct packet_info* p) { struct iphdr* ih; DEBUG("* parse IP\n"); if (len < sizeof(struct iphdr)) return -1; ih = (struct iphdr*)*buf; DEBUG("*** IP SRC: %s\n", ip_sprintf(ih->saddr)); DEBUG("*** IP DST: %s\n", ip_sprintf(ih->daddr)); p->ip_src = ih->saddr; p->ip_dst = ih->daddr; p->pkt_types |= PKT_TYPE_IP; DEBUG("IP proto: %d\n", ih->protocol); switch (ih->protocol) { case IPPROTO_UDP: p->pkt_types |= PKT_TYPE_UDP; break; /* all others set the type and return. no more parsing */ case IPPROTO_ICMP: p->pkt_types |= PKT_TYPE_ICMP; return 0; case IPPROTO_TCP: p->pkt_types |= PKT_TYPE_TCP; return 0; } *buf = *buf + ih->ihl * 4; return len - ih->ihl * 4; } static int parse_udp_header(unsigned char** buf, int len, struct packet_info* p) { struct udphdr* uh; if (len < sizeof(struct udphdr)) return -1; uh = (struct udphdr*)*buf; DEBUG("UPD dest port: %d\n", ntohs(uh->dest)); p->tcpudp_port = ntohs(uh->dest); *buf = *buf + 8; len = len - 8; if (p->tcpudp_port == 698) /* OLSR */ return parse_olsr_packet(buf, len, p); if (p->tcpudp_port == BAT_PORT) /* batman */ return parse_batman_packet(buf, len, p); if (p->tcpudp_port == 9256 || p->tcpudp_port == 9257 ) /* MeshCruzer */ return parse_meshcruzer_packet(buf, len, p, p->tcpudp_port); return 0; } static int parse_olsr_packet(unsigned char** buf, int len, struct packet_info* p) { struct olsr* oh; int number, i, msgtype; if (len < sizeof(struct olsr)) return -1; oh = (struct olsr*)*buf; // TODO: more than one olsr messages can be in one packet msgtype = oh->olsr_msg[0].olsr_msgtype; DEBUG("OLSR msgtype: %d\n*** ", msgtype); p->pkt_types |= PKT_TYPE_OLSR; p->olsr_type = msgtype; if (msgtype == LQ_HELLO_MESSAGE || msgtype == LQ_TC_MESSAGE ) p->pkt_types |= PKT_TYPE_OLSR_LQ; if (msgtype == HELLO_MESSAGE) { number = (ntohs(oh->olsr_msg[0].olsr_msgsize) - 12) / sizeof(struct hellomsg); DEBUG("HELLO %d\n", number); p->olsr_neigh = number; } if (msgtype == LQ_HELLO_MESSAGE) { number = (ntohs(oh->olsr_msg[0].olsr_msgsize) - 16) / 12; DEBUG("LQ_HELLO %d (%d)\n", number, (ntohs(oh->olsr_msg[0].olsr_msgsize) - 16)); p->olsr_neigh = number; } #if 0 /* XXX: tc messages are relayed. so we would have to find the originating node (IP) and store the information there. skip for now */ if (msgtype == TC_MESSAGE) { number = (ntohs(oh->olsr_msg[0].olsr_msgsize)-12) / sizeof(struct tcmsg); DEBUG("TC %d\n", number); p->olsr_tc = number; } if (msgtype == LQ_TC_MESSAGE) { number = (ntohs(oh->olsr_msg[0].olsr_msgsize)-16) / 8; DEBUG("LQ_TC %d (%d)\n", number, (ntohs(oh->olsr_msg[0].olsr_msgsize)-16)); p->olsr_tc = number; } #endif if (msgtype == HNA_MESSAGE) { /* same here, but we assume that nodes which relay a HNA with a default gateway know how to contact the gw, so have a indirect connection to a GW themselves */ struct hnapair* hna; number = (ntohs(oh->olsr_msg[0].olsr_msgsize) - 12) / sizeof(struct hnapair); DEBUG("HNA NUM: %d (%d) [%d]\n", number, ntohs(oh->olsr_msg[0].olsr_msgsize), (int)sizeof(struct hnapair) ); for (i = 0; i < number; i++) { hna = &(oh->olsr_msg[0].message.hna.hna_net[i]); DEBUG("HNA %s", ip_sprintf(hna->addr)); DEBUG("/%s\n", ip_sprintf(hna->netmask)); if (hna->addr == 0 && hna->netmask == 0) p->pkt_types |= PKT_TYPE_OLSR_GW; } } /* done for good */ return 0; } static int parse_batman_packet(unsigned char** buf, int len, struct packet_info* p) { p->pkt_types |= PKT_TYPE_BATMAN; return 0; } static int parse_meshcruzer_packet(unsigned char** buf, int len, struct packet_info* p, int port) { p->pkt_types |= PKT_TYPE_MESHZ; return 0; } horst-3.0/protocol_parser.h000066400000000000000000000017411152373700300161050ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _PROTOCOL_PARSER_H_ #define _PROTOCOL_PARSER_H_ struct packet_info; int parse_packet(unsigned char* buf, int len, struct packet_info* p); #endif horst-3.0/util.c000066400000000000000000000154421152373700300136430ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include "util.h" #include "ieee80211.h" struct pkt_names { char c; const char* name; }; /* a list of packet type names for easier indexing with padding */ static struct pkt_names mgmt_names[] = { { 'a', "ASOCRQ" }, /* IEEE80211_STYPE_ASSOC_REQ 0x0000 */ { 'A', "ASOCRP" }, /* IEEE80211_STYPE_ASSOC_RESP 0x0010 */ { 'a', "REASRQ" }, /* IEEE80211_STYPE_REASSOC_REQ 0x0020 */ { 'A', "REASRP" }, /* IEEE80211_STYPE_REASSOC_RESP 0x0030 */ { 'p', "PROBRQ" }, /* IEEE80211_STYPE_PROBE_REQ 0x0040 */ { 'P', "PROBRP" }, /* IEEE80211_STYPE_PROBE_RESP 0x0050 */ {}, {}, /* unused */ { 'B', "BEACON" }, /* IEEE80211_STYPE_BEACON 0x0080 */ { 't', "ATIM" }, /* IEEE80211_STYPE_ATIM 0x0090 */ { 'D', "DISASC" }, /* IEEE80211_STYPE_DISASSOC 0x00A0 */ { 'u', "AUTH" }, /* IEEE80211_STYPE_AUTH 0x00B0 */ { 'U', "DEAUTH" }, /* IEEE80211_STYPE_DEAUTH 0x00C0 */ { 'T', "ACTION" }, /* IEEE80211_STYPE_ACTION 0x00D0 */ }; static struct pkt_names ctrl_names[] = { { 's', "PSPOLL" }, /* IEEE80211_STYPE_PSPOLL 0x00A0 */ { 'R', "RTS" }, /* IEEE80211_STYPE_RTS 0x00B0 */ { 'C', "CTS" }, /* IEEE80211_STYPE_CTS 0x00C0 */ { 'K', "ACK" }, /* IEEE80211_STYPE_ACK 0x00D0 */ { 'f', "CFEND" }, /* IEEE80211_STYPE_CFEND 0x00E0 */ { 'f', "CFENDK" }, /* IEEE80211_STYPE_CFENDACK 0x00F0 */ }; static struct pkt_names data_names[] = { { 'D', "DATA" }, /* IEEE80211_STYPE_DATA 0x0000 */ { 'F', "DCFACK" }, /* IEEE80211_STYPE_DATA_CFACK 0x0010 */ { 'F', "DCFPLL" }, /* IEEE80211_STYPE_DATA_CFPOLL 0x0020 */ { 'F', "DCFKPL" }, /* IEEE80211_STYPE_DATA_CFACKPOLL 0x0030 */ { 'n', "NULL" }, /* IEEE80211_STYPE_NULLFUNC 0x0040 */ { 'f', "CFACK" }, /* IEEE80211_STYPE_CFACK 0x0050 */ { 'f', "CFPOLL" }, /* IEEE80211_STYPE_CFPOLL 0x0060 */ { 'f', "CFCKPL" }, /* IEEE80211_STYPE_CFACKPOLL 0x0070 */ { 'Q', "QDATA" }, /* IEEE80211_STYPE_QOS_DATA 0x0080 */ { 'F', "QDCFCK" }, /* IEEE80211_STYPE_QOS_DATA_CFACK 0x0090 */ { 'F', "QDCFPL" }, /* IEEE80211_STYPE_QOS_DATA_CFPOLL 0x00A0 */ { 'F', "QDCFKP" }, /* IEEE80211_STYPE_QOS_DATA_CFACKPOLL 0x00B0 */ { 'N', "QDNULL" }, /* IEEE80211_STYPE_QOS_NULLFUNC 0x00C0 */ { 'f', "QCFACK" }, /* IEEE80211_STYPE_QOS_CFACK 0x00D0 */ { 'f', "QCFPLL" }, /* IEEE80211_STYPE_QOS_CFPOLL 0x00E0 */ { 'f', "QCFKPL" }, /* IEEE80211_STYPE_QOS_CFACKPOLL 0x00F0 */ }; #define DATA_NAME_INDEX(_i) (((_i) & IEEE80211_FCTL_STYPE)>>4) #define MGMT_NAME_INDEX(_i) (((_i) & IEEE80211_FCTL_STYPE)>>4) #define CTRL_NAME_INDEX(_i) ((((_i) & IEEE80211_FCTL_STYPE)>>4)-10) int normalize(float oval, int max_val, int max) { int val; val= (oval / max_val) * max; if (val > max) /* cap if still bigger */ val = max; if (val == 0 && oval > 0) val = 1; if (val < 0) val = 0; return val; } void dump_packet(const unsigned char* buf, int len) { int i; for (i = 0; i < len; i++) { if ((i % 2) == 0) DEBUG(" "); if ((i % 16) == 0) DEBUG("\n"); DEBUG("%02x", buf[i]); } DEBUG("\n"); } const char* ether_sprintf(const unsigned char *mac) { static char etherbuf[18]; snprintf(etherbuf, sizeof(etherbuf), "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); return etherbuf; } const char* ether_sprintf_short(const unsigned char *mac) { static char etherbuf[5]; snprintf(etherbuf, sizeof(etherbuf), "%02x%02x", mac[4], mac[5]); return etherbuf; } const char* ip_sprintf(const unsigned int ip) { static char ipbuf[18]; unsigned char* cip = (unsigned char*)&ip; snprintf(ipbuf, sizeof(ipbuf), "%d.%d.%d.%d", cip[0], cip[1], cip[2], cip[3]); return ipbuf; } const char* ip_sprintf_short(const unsigned int ip) { static char ipbuf[5]; unsigned char* cip = (unsigned char*)&ip; snprintf(ipbuf, sizeof(ipbuf), ".%d", cip[3]); return ipbuf; } void convert_string_to_mac(const char* string, unsigned char* mac) { int c; for(c = 0; c < 6 && string; c++) { int x = 0; if (string) sscanf(string, "%x", &x); mac[c] = x; string = strchr(string, ':'); if (string) string++; } } char get_packet_type_char(int type) { switch (type & IEEE80211_FCTL_FTYPE) { case IEEE80211_FTYPE_MGMT: if (MGMT_NAME_INDEX(type) < sizeof(mgmt_names)/sizeof(struct pkt_names)) { if (mgmt_names[MGMT_NAME_INDEX(type)].c) return mgmt_names[MGMT_NAME_INDEX(type)].c; } break; case IEEE80211_FTYPE_CTL: if (CTRL_NAME_INDEX(type) < sizeof(ctrl_names)/sizeof(struct pkt_names)) { if (ctrl_names[CTRL_NAME_INDEX(type)].c) return ctrl_names[CTRL_NAME_INDEX(type)].c; } break; case IEEE80211_FTYPE_DATA: if (DATA_NAME_INDEX(type) < sizeof(data_names)/sizeof(struct pkt_names)) { if (data_names[DATA_NAME_INDEX(type)].c) return data_names[DATA_NAME_INDEX(type)].c; } break; } return '?'; } const char* get_packet_type_name(int type) { switch (type & IEEE80211_FCTL_FTYPE) { case IEEE80211_FTYPE_MGMT: if (MGMT_NAME_INDEX(type) < sizeof(mgmt_names)/sizeof(struct pkt_names)) { if (mgmt_names[MGMT_NAME_INDEX(type)].c) return mgmt_names[MGMT_NAME_INDEX(type)].name; } break; case IEEE80211_FTYPE_CTL: if (CTRL_NAME_INDEX(type) < sizeof(ctrl_names)/sizeof(struct pkt_names)) { if (ctrl_names[CTRL_NAME_INDEX(type)].c) return ctrl_names[CTRL_NAME_INDEX(type)].name; } break; case IEEE80211_FTYPE_DATA: if (DATA_NAME_INDEX(type) < sizeof(data_names)/sizeof(struct pkt_names)) { if (data_names[DATA_NAME_INDEX(type)].c) return data_names[DATA_NAME_INDEX(type)].name; } break; } return "UNKNOW"; } const char* kilo_mega_ize(unsigned int val) { static char buf[20]; char c = 0; int rest; if (val >= 1024) { /* kilo */ rest = (val & 1023) / 102.4; /* only one digit */ val = val >> 10; c = 'k'; } if (val >= 1024) { /* mega */ rest = (val & 1023) / 102.4; /* only one digit */ val = val >> 10; c = 'M'; } if (c) snprintf(buf, sizeof(buf), "%d.%d%c", val, rest, c); else snprintf(buf, sizeof(buf), "%d", val); return buf; } /* simple ilog2 implementation */ int ilog2(int x) { int n; for (n = 0; !(x & 1); n++) x = x >> 1; return n; } horst-3.0/util.h000066400000000000000000000050541152373700300136460ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _UTIL_H_ #define _UTIL_H_ #include #include #include #if DO_DEBUG #define DEBUG(...) printf(__VA_ARGS__) #else #define DEBUG(...) #endif #if BYTE_ORDER == LITTLE_ENDIAN #define le64toh(x) (x) #define le32toh(x) (x) #define le16toh(x) (x) #define htole64(x) (x) #define htole32(x) (x) #define htole16(x) (x) #else #define le64toh(x) bswap_64(x) #define le32toh(x) bswap_32(x) #define le16toh(x) bswap_16(x) #define htole64(x) bswap_64(x) #define htole32(x) bswap_32(x) #define htole16(x) bswap_16(x) #endif void dump_packet(const unsigned char* buf, int len); const char* ether_sprintf(const unsigned char *mac); const char* ether_sprintf_short(const unsigned char *mac); const char* ip_sprintf(const unsigned int ip); const char* ip_sprintf_short(const unsigned int ip); void convert_string_to_mac(const char* string, unsigned char* mac); int normalize(float val, int max_val, int max); static inline int normalize_db(int val, int max) { if (val <= 30) return 0; else if (val >= 100) return max; else return normalize(val - 30, 70, max); } char get_packet_type_char(int type); const char* get_packet_type_name(int type); const char* kilo_mega_ize(unsigned int val); #define MAC_NOT_EMPTY(_mac) (_mac[0] || _mac[1] || _mac[2] || _mac[3] || _mac[4] || _mac[5]) #define MAC_EMPTY(_mac) (!_mac[0] && !_mac[1] && !_mac[2] && !_mac[3] && !_mac[4] && !_mac[5]) #define TOGGLE_BIT(_x, _m) (_x) ^= (_m) #define max(_x, _y) ((_x) > (_y) ? (_x) : (_y)) #define min(_x, _y) ((_x) < (_y) ? (_x) : (_y)) #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) static inline __attribute__((const)) int is_power_of_2(unsigned long n) { return (n != 0 && ((n & (n - 1)) == 0)); } int ilog2(int x); #endif horst-3.0/wext.c000066400000000000000000000052161152373700300136530ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "wext.h" #include "util.h" int wext_set_freq(int fd, const char* devname, int freq) { struct iwreq iwr; memset(&iwr, 0, sizeof(iwr)); strncpy(iwr.ifr_name, devname, IFNAMSIZ); freq *= 100000; iwr.u.freq.m = freq; iwr.u.freq.e = 1; if (ioctl(fd, SIOCSIWFREQ, &iwr) < 0) { printlog("ERROR: wext set channel"); return 0; } return 1; } int wext_get_freq(int fd, const char* devname) { struct iwreq iwr; memset(&iwr, 0, sizeof(iwr)); strncpy(iwr.ifr_name, devname, IFNAMSIZ); if (ioctl(fd, SIOCGIWFREQ, &iwr) < 0) { printlog("ERROR: wext get freq"); return 0; } DEBUG("FREQ %d %d\n", iwr.u.freq.m, iwr.u.freq.e); return iwr.u.freq.m; } int wext_get_channels(int fd, const char* devname, struct chan_freq channels[MAX_CHANNELS]) { struct iwreq iwr; struct iw_range range; int i; memset(&iwr, 0, sizeof(iwr)); memset(&range, 0, sizeof(range)); strncpy(iwr.ifr_name, devname, IFNAMSIZ); iwr.u.data.pointer = (caddr_t) ⦥ iwr.u.data.length = sizeof(range); iwr.u.data.flags = 0; if (ioctl(fd, SIOCGIWRANGE, &iwr) < 0) { printlog("ERROR: wext get channel list"); return 0; } if(range.we_version_compiled < 16) { printlog("ERROR: wext version %d too old to get channels", range.we_version_compiled); return 0; } for(i = 0; i < range.num_frequency && i < MAX_CHANNELS; i++) { DEBUG(" Channel %.2d: %dMHz\n", range.freq[i].i, range.freq[i].m); channels[i].chan = range.freq[i].i; /* different drivers return different frequencies * (e.g. ipw2200 vs mac80211) try to fix them up here */ if (range.freq[i].m > 100000000) channels[i].freq = range.freq[i].m / 100000; else channels[i].freq = range.freq[i].m; } return range.num_frequency; } horst-3.0/wext.h000066400000000000000000000021211152373700300136500ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2011 Bruno Randolf (br1@einfach.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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _WEXT_H_ #define _WEXT_H_ #include "main.h" int wext_set_freq(int fd, const char* devname, int chan); int wext_get_freq(int fd, const char* devname); int wext_get_channels(int fd, const char* devname, struct chan_freq c[MAX_CHANNELS]); #endif // _WEXT_H_