pax_global_header00006660000000000000000000000064124127441260014515gustar00rootroot0000000000000052 comment=d6d5aa7ea0a74eabe02271cb5e1de55920bae68e horst-4.2/000077500000000000000000000000001241274412600125215ustar00rootroot00000000000000horst-4.2/.gitignore000066400000000000000000000000511241274412600145050ustar00rootroot00000000000000horst *.o .buildflags .cproject .project horst-4.2/LICENSE000066400000000000000000000431331241274412600135320ustar00rootroot00000000000000 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-4.2/Makefile000066400000000000000000000103741241274412600141660ustar00rootroot00000000000000# horst - Highly Optimized Radio Scanning Tool # # Copyright (C) 2005-2014 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. # build options DEBUG=0 PCAP=0 NAME=horst OBJS=main.o capture$(if $(filter 1,$(PCAP)),-pcap).o protocol_parser.o \ protocol_parser_wlan.o network.o wext.o node.o essid.o channel.o \ util.o wlan_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 control.o \ radiotap/radiotap.o LIBS=-lncurses -lm CFLAGS+=-Wall -Wextra -g -I. ifeq ($(DEBUG),1) CFLAGS+=-DDO_DEBUG endif ifeq ($(PCAP),1) CFLAGS+=-DPCAP LIBS+=-lpcap endif .PHONY: force all: $(NAME) # dependencies, generated with 'gcc -MM *.c' and pasted here average.o: average.c average.h util.h capture.o: capture.c capture.h util.h capture-pcap.o: capture-pcap.c capture.h util.h channel.o: channel.c main.h ccan/list/list.h average.h channel.h \ wlan80211.h util.h wext.h control.o: control.c main.h ccan/list/list.h average.h channel.h \ wlan80211.h control.h display.o: display.c display.h main.h ccan/list/list.h average.h \ channel.h wlan80211.h display-channel.o: display-channel.c display.h main.h ccan/list/list.h \ average.h channel.h wlan80211.h network.h display-essid.o: display-essid.c display.h main.h ccan/list/list.h \ average.h channel.h wlan80211.h util.h display-filter.o: display-filter.c display.h main.h ccan/list/list.h \ average.h channel.h wlan80211.h util.h network.h display-help.o: display-help.c display.h main.h ccan/list/list.h \ average.h channel.h wlan80211.h wlan_util.h display-history.o: display-history.c display.h main.h ccan/list/list.h \ average.h channel.h wlan80211.h util.h wlan_util.h display-main.o: display-main.c display.h main.h ccan/list/list.h \ average.h channel.h wlan80211.h util.h wlan_util.h olsr_header.h \ batman_adv_header-14.h listsort.h display-spectrum.o: display-spectrum.c display.h main.h ccan/list/list.h \ average.h channel.h wlan80211.h util.h display-statistics.o: display-statistics.c display.h main.h \ ccan/list/list.h average.h channel.h wlan80211.h util.h wlan_util.h essid.o: essid.c main.h ccan/list/list.h average.h channel.h wlan80211.h \ util.h essid.h ieee80211_util.o: ieee80211_util.c ieee80211_util.h wlan80211.h main.h \ ccan/list/list.h average.h channel.h util.h listsort.o: listsort.c ccan/list/list.h listsort.h main.o: main.c main.h ccan/list/list.h average.h channel.h wlan80211.h \ util.h capture.h protocol_parser.h network.h display.h wlan_util.h \ ieee80211_util.h control.h node.h essid.h network.o: network.c main.h ccan/list/list.h average.h channel.h \ wlan80211.h util.h network.h node.o: node.c main.h ccan/list/list.h average.h channel.h wlan80211.h \ util.h essid.h protocol_parser.o: protocol_parser.c olsr_header.h batman_header.h \ batman_adv_header-14.h main.h ccan/list/list.h average.h channel.h \ wlan80211.h util.h protocol_parser_wlan.o: protocol_parser_wlan.c prism_header.h \ radiotap/radiotap.h radiotap/radiotap_iter.h radiotap/radiotap.h \ wlan80211.h wlan_util.h main.h ccan/list/list.h average.h channel.h \ util.h util.o: util.c util.h wext.o: wext.c wext.h channel.h main.h ccan/list/list.h average.h \ wlan80211.h util.h wlan_util.o: wlan_util.c main.h ccan/list/list.h average.h channel.h \ wlan80211.h util.h wlan_util.h $(NAME): $(OBJS) $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(OBJS): .buildflags check: sparse *.[ch] clean: -rm -f *.o radiotap/*.o *~ -rm -f $(NAME) -rm -f .buildflags .buildflags: force echo '$(CFLAGS)' | cmp -s - $@ || echo '$(CFLAGS)' > $@ horst-4.2/README000066400000000000000000000060721241274412600134060ustar00rootroot00000000000000 HORST - Horsts OLSR Radio Scanning Tool (or) HORST - Highly Optimized Radio Scanning Tool ------------------------------------------------------------------------------- Copyright (C) 2005-2014 Bruno Randolf (br1@einfach.org) Licensed under the GNU Public License (GPL) V2 = Overview = “horst” is a small, lightweight IEEE802.11 wireless LAN analyzer with a text interface. Its basic function is similar to tcpdump, Wireshark or Kismet, but it’s much smaller and shows different, aggregated information which is not easily available from other tools. It is mainly targeted at debugging wireless LANs with a focus on ad-hoc (IBSS) mode in larger mesh networks. It can be useful to get a quick overview of what’s going on on all wireless LAN channels and to identify problems. See the man page for more detailed and up-to-date information: $ man -l horst.1 (or) $ nroff -mandoc horst.1 Also see: http://br1.einfach.org/tech/horst/ = Building = Official git repository: git://br1.einfach.org/horst GitHub clone: https://github.com/br101/horst "horst" is just a simple tool, and "libncurses" is the only requirement (be sure to install it's header files too). Therefore building is as simple as typing: $ make To see very detailled debugging output you can use $ make DEBUG=1 To experimentally build for Mac OSX or other Unix using libpcap use: $ make PCAP=1 Please note that PCAP and OSX support is not well tested and some features, like getting or setting the channel are not implemented on OSX. = Background = "horst" was created to fill a need in the Wireless Mesh networking / Freifunk community of Berlin but has since grown to be a useful tool for all kinds of Wireless networks. With the usual wireless tools like iw, iwconfig and iwspy and even kismet or WireShark it is hard to measure the received signal strength (RSSI) of all available access points, stations and ad-hoc networks in a given location. It's especially difficult to differentiate the different nodes which form an ad-hoc network. This information however is very important for setting up, debugging and optimizing wireless mesh networks and antenna positions. "horst" aims to fill this gap and lists each single node of an ad-hoc network separately, showing the signal strength (RSSI) 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) and get a general overview of what's going on in the "air". To do this, "horst" uses the monitor mode including radiotap headers (or for older drivers prism2 headers) for the signal strength information of the wlan cards and listens to all packets which come in the wireless interface. The packets are summarized by the MAC address of the sending node, analyzed and aggregated and displayed in a simple text (ncurses) interface. = Contributors = Thanks to the following persons for contributions: Horst Krause Sven-Ola Tuecke Robert Schuster Jonathan Guerin David Rowe Antoine Beaupré Rami Refaeli Joerg Albert horst-4.2/TODO000066400000000000000000000001531241274412600132100ustar00rootroot00000000000000TODO: ----- * 802.11ac support * Automatically create monitor interface * Integrate 'iw survey dump' info horst-4.2/average.c000066400000000000000000000035211241274412600143000ustar00rootroot00000000000000/* * 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)) err(1, "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-4.2/average.h000066400000000000000000000012111241274412600142770ustar00rootroot00000000000000#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-4.2/batman_adv_header-14.h000066400000000000000000000130501241274412600165170ustar00rootroot00000000000000/* * Copyright (C) 2007-2011 B.A.T.M.A.N. contributors: * * Marek Lindner, Simon Wunderlich * * 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 _NET_BATMAN_ADV_PACKET_H_ #define _NET_BATMAN_ADV_PACKET_H_ #define ETH_ALEN 6 #define ETH_P_BATMAN 0x4305 /* unofficial/not registered Ethertype */ enum bat_packettype { BAT_OGM = 0x01, BAT_ICMP = 0x02, BAT_UNICAST = 0x03, BAT_BCAST = 0x04, BAT_VIS = 0x05, BAT_UNICAST_FRAG = 0x06, BAT_TT_QUERY = 0x07, BAT_ROAM_ADV = 0x08 }; /* this file is included by batctl which needs these defines */ #define COMPAT_VERSION 14 enum batman_flags { PRIMARIES_FIRST_HOP = 1 << 4, VIS_SERVER = 1 << 5, DIRECTLINK = 1 << 6 }; /* ICMP message types */ enum icmp_packettype { ECHO_REPLY = 0, DESTINATION_UNREACHABLE = 3, ECHO_REQUEST = 8, TTL_EXCEEDED = 11, PARAMETER_PROBLEM = 12 }; /* vis defines */ enum vis_packettype { VIS_TYPE_SERVER_SYNC = 0, VIS_TYPE_CLIENT_UPDATE = 1 }; /* fragmentation defines */ enum unicast_frag_flags { UNI_FRAG_HEAD = 1 << 0, UNI_FRAG_LARGETAIL = 1 << 1 }; /* TT_QUERY subtypes */ #define TT_QUERY_TYPE_MASK 0x3 enum tt_query_packettype { TT_REQUEST = 0, TT_RESPONSE = 1 }; /* TT_QUERY flags */ enum tt_query_flags { TT_FULL_TABLE = 1 << 2 }; /* TT_CLIENT flags. * Flags from 1 to 1 << 7 are sent on the wire, while flags from 1 << 8 to * 1 << 15 are used for local computation only */ enum tt_client_flags { TT_CLIENT_DEL = 1 << 0, TT_CLIENT_ROAM = 1 << 1, TT_CLIENT_WIFI = 1 << 2, TT_CLIENT_NOPURGE = 1 << 8, TT_CLIENT_NEW = 1 << 9, TT_CLIENT_PENDING = 1 << 10 }; struct batman_ogm_packet { uint8_t packet_type; uint8_t version; /* batman version field */ uint8_t ttl; uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */ uint32_t seqno; uint8_t orig[6]; uint8_t prev_sender[6]; uint8_t gw_flags; /* flags related to gateway class */ uint8_t tq; uint8_t tt_num_changes; uint8_t ttvn; /* translation table version number */ uint16_t tt_crc; } __attribute__ ((packed)); #define BATMAN_OGM_LEN sizeof(struct batman_ogm_packet) struct icmp_packet { uint8_t packet_type; uint8_t version; /* batman version field */ uint8_t ttl; uint8_t msg_type; /* see ICMP message types above */ uint8_t dst[6]; uint8_t orig[6]; uint16_t seqno; uint8_t uid; uint8_t reserved; } __attribute__ ((packed)); #define BAT_RR_LEN 16 /* icmp_packet_rr must start with all fields from imcp_packet * as this is assumed by code that handles ICMP packets */ struct icmp_packet_rr { uint8_t packet_type; uint8_t version; /* batman version field */ uint8_t ttl; uint8_t msg_type; /* see ICMP message types above */ uint8_t dst[6]; uint8_t orig[6]; uint16_t seqno; uint8_t uid; uint8_t rr_cur; uint8_t rr[BAT_RR_LEN][ETH_ALEN]; } __attribute__ ((packed)); struct unicast_packet { uint8_t packet_type; uint8_t version; /* batman version field */ uint8_t ttl; uint8_t ttvn; /* destination translation table version number */ uint8_t dest[6]; } __attribute__ ((packed)); struct unicast_frag_packet { uint8_t packet_type; uint8_t version; /* batman version field */ uint8_t ttl; uint8_t ttvn; /* destination translation table version number */ uint8_t dest[6]; uint8_t flags; uint8_t align; uint8_t orig[6]; uint16_t seqno; } __attribute__ ((packed)); struct bcast_packet { uint8_t packet_type; uint8_t version; /* batman version field */ uint8_t ttl; uint8_t reserved; uint32_t seqno; uint8_t orig[6]; } __attribute__ ((packed)); struct vis_packet { uint8_t packet_type; uint8_t version; /* batman version field */ uint8_t ttl; /* TTL */ uint8_t vis_type; /* which type of vis-participant sent this? */ uint32_t seqno; /* sequence number */ uint8_t entries; /* number of entries behind this struct */ uint8_t reserved; uint8_t vis_orig[6]; /* originator that announces its neighbors */ uint8_t target_orig[6]; /* who should receive this packet */ uint8_t sender_orig[6]; /* who sent or rebroadcasted this packet */ } __attribute__ ((packed)); struct tt_query_packet { uint8_t packet_type; uint8_t version; /* batman version field */ uint8_t ttl; /* the flag field is a combination of: * - TT_REQUEST or TT_RESPONSE * - TT_FULL_TABLE */ uint8_t flags; uint8_t dst[ETH_ALEN]; uint8_t src[ETH_ALEN]; /* the ttvn field is: * if TT_REQUEST: ttvn that triggered the * request * if TT_RESPONSE: new ttvn for the src * orig_node */ uint8_t ttvn; /* tt_data field is: * if TT_REQUEST: crc associated with the * ttvn * if TT_RESPONSE: table_size */ uint16_t tt_data; } __attribute__ ((packed)); struct roam_adv_packet { uint8_t packet_type; uint8_t version; uint8_t ttl; uint8_t reserved; uint8_t dst[ETH_ALEN]; uint8_t src[ETH_ALEN]; uint8_t client[ETH_ALEN]; } __attribute__ ((packed)); struct tt_change { uint8_t flags; uint8_t addr[ETH_ALEN]; } __attribute__ ((packed)); #endif /* _NET_BATMAN_ADV_PACKET_H_ */ horst-4.2/batman_adv_header-15.h000066400000000000000000000402641241274412600165270ustar00rootroot00000000000000/* Copyright (C) 2007-2014 B.A.T.M.A.N. contributors: * * Marek Lindner, Simon Wunderlich * * 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, see . */ #ifndef _NET_BATMAN_ADV_PACKET_H_ #define _NET_BATMAN_ADV_PACKET_H_ #define BIT(_x) (1<_x) typedef u_int16_t __be16; typedef u_int32_t __be32; #define ETH_ALEN 6 #define __BIG_ENDIAN_BITFIELD /* todo */ /** * enum batadv_packettype - types for batman-adv encapsulated packets * @BATADV_IV_OGM: originator messages for B.A.T.M.A.N. IV * @BATADV_BCAST: broadcast packets carrying broadcast payload * @BATADV_CODED: network coded packets * * @BATADV_UNICAST: unicast packets carrying unicast payload traffic * @BATADV_UNICAST_FRAG: unicast packets carrying a fragment of the original * payload packet * @BATADV_UNICAST_4ADDR: unicast packet including the originator address of * the sender * @BATADV_ICMP: unicast packet like IP ICMP used for ping or traceroute * @BATADV_UNICAST_TVLV: unicast packet carrying TVLV containers */ enum batadv_packettype { /* 0x00 - 0x3f: local packets or special rules for handling */ BATADV_IV_OGM = 0x00, BATADV_BCAST = 0x01, BATADV_CODED = 0x02, /* 0x40 - 0x7f: unicast */ #define BATADV_UNICAST_MIN 0x40 BATADV_UNICAST = 0x40, BATADV_UNICAST_FRAG = 0x41, BATADV_UNICAST_4ADDR = 0x42, BATADV_ICMP = 0x43, BATADV_UNICAST_TVLV = 0x44, #define BATADV_UNICAST_MAX 0x7f /* 0x80 - 0xff: reserved */ }; /** * enum batadv_subtype - packet subtype for unicast4addr * @BATADV_P_DATA: user payload * @BATADV_P_DAT_DHT_GET: DHT request message * @BATADV_P_DAT_DHT_PUT: DHT store message * @BATADV_P_DAT_CACHE_REPLY: ARP reply generated by DAT */ enum batadv_subtype { BATADV_P_DATA = 0x01, BATADV_P_DAT_DHT_GET = 0x02, BATADV_P_DAT_DHT_PUT = 0x03, BATADV_P_DAT_CACHE_REPLY = 0x04, }; /* this file is included by batctl which needs these defines */ #define BATADV_COMPAT_VERSION 15 /** * enum batadv_iv_flags - flags used in B.A.T.M.A.N. IV OGM packets * @BATADV_NOT_BEST_NEXT_HOP: flag is set when ogm packet is forwarded and was * previously received from someone else than the best neighbor. * @BATADV_PRIMARIES_FIRST_HOP: flag is set when the primary interface address * is used, and the packet travels its first hop. * @BATADV_DIRECTLINK: flag is for the first hop or if rebroadcasted from a * one hop neighbor on the interface where it was originally received. */ enum batadv_iv_flags { BATADV_NOT_BEST_NEXT_HOP = BIT(0), BATADV_PRIMARIES_FIRST_HOP = BIT(1), BATADV_DIRECTLINK = BIT(2), }; /* ICMP message types */ enum batadv_icmp_packettype { BATADV_ECHO_REPLY = 0, BATADV_DESTINATION_UNREACHABLE = 3, BATADV_ECHO_REQUEST = 8, BATADV_TTL_EXCEEDED = 11, BATADV_PARAMETER_PROBLEM = 12, }; /* tt data subtypes */ #define BATADV_TT_DATA_TYPE_MASK 0x0F /** * enum batadv_tt_data_flags - flags for tt data tvlv * @BATADV_TT_OGM_DIFF: TT diff propagated through OGM * @BATADV_TT_REQUEST: TT request message * @BATADV_TT_RESPONSE: TT response message * @BATADV_TT_FULL_TABLE: contains full table to replace existing table */ enum batadv_tt_data_flags { BATADV_TT_OGM_DIFF = BIT(0), BATADV_TT_REQUEST = BIT(1), BATADV_TT_RESPONSE = BIT(2), BATADV_TT_FULL_TABLE = BIT(4), }; /* BATADV_TT_CLIENT flags. * Flags from BIT(0) to BIT(7) are sent on the wire, while flags from BIT(8) to * BIT(15) are used for local computation only. * Flags from BIT(4) to BIT(7) are kept in sync with the rest of the network. */ enum batadv_tt_client_flags { BATADV_TT_CLIENT_DEL = BIT(0), BATADV_TT_CLIENT_ROAM = BIT(1), BATADV_TT_CLIENT_WIFI = BIT(4), BATADV_TT_CLIENT_ISOLA = BIT(5), BATADV_TT_CLIENT_NOPURGE = BIT(8), BATADV_TT_CLIENT_NEW = BIT(9), BATADV_TT_CLIENT_PENDING = BIT(10), BATADV_TT_CLIENT_TEMP = BIT(11), }; /** * batadv_vlan_flags - flags for the four MSB of any vlan ID field * @BATADV_VLAN_HAS_TAG: whether the field contains a valid vlan tag or not */ enum batadv_vlan_flags { BATADV_VLAN_HAS_TAG = BIT(15), }; /* claim frame types for the bridge loop avoidance */ enum batadv_bla_claimframe { BATADV_CLAIM_TYPE_CLAIM = 0x00, BATADV_CLAIM_TYPE_UNCLAIM = 0x01, BATADV_CLAIM_TYPE_ANNOUNCE = 0x02, BATADV_CLAIM_TYPE_REQUEST = 0x03, }; /** * enum batadv_tvlv_type - tvlv type definitions * @BATADV_TVLV_GW: gateway tvlv * @BATADV_TVLV_DAT: distributed arp table tvlv * @BATADV_TVLV_NC: network coding tvlv * @BATADV_TVLV_TT: translation table tvlv * @BATADV_TVLV_ROAM: roaming advertisement tvlv */ enum batadv_tvlv_type { BATADV_TVLV_GW = 0x01, BATADV_TVLV_DAT = 0x02, BATADV_TVLV_NC = 0x03, BATADV_TVLV_TT = 0x04, BATADV_TVLV_ROAM = 0x05, }; #pragma pack(2) /* the destination hardware field in the ARP frame is used to * transport the claim type and the group id */ struct batadv_bla_claim_dst { uint8_t magic[3]; /* FF:43:05 */ uint8_t type; /* bla_claimframe */ __be16 group; /* group id */ }; #pragma pack() /** * struct batadv_ogm_packet - ogm (routing protocol) packet * @packet_type: batman-adv packet type, part of the general header * @version: batman-adv protocol version, part of the genereal header * @ttl: time to live for this packet, part of the genereal header * @flags: contains routing relevant flags - see enum batadv_iv_flags * @tvlv_len: length of tvlv data following the ogm header */ struct batadv_ogm_packet { uint8_t packet_type; uint8_t version; uint8_t ttl; uint8_t flags; __be32 seqno; uint8_t orig[ETH_ALEN]; uint8_t prev_sender[ETH_ALEN]; uint8_t reserved; uint8_t tq; __be16 tvlv_len; /* __packed is not needed as the struct size is divisible by 4, * and the largest data type in this struct has a size of 4. */ }; #define BATADV_OGM_HLEN sizeof(struct batadv_ogm_packet) /** * batadv_icmp_header - common members among all the ICMP packets * @packet_type: batman-adv packet type, part of the general header * @version: batman-adv protocol version, part of the genereal header * @ttl: time to live for this packet, part of the genereal header * @msg_type: ICMP packet type * @dst: address of the destination node * @orig: address of the source node * @uid: local ICMP socket identifier * @align: not used - useful for alignment purposes only * * This structure is used for ICMP packets parsing only and it is never sent * over the wire. The alignment field at the end is there to ensure that * members are padded the same way as they are in real packets. */ struct batadv_icmp_header { uint8_t packet_type; uint8_t version; uint8_t ttl; uint8_t msg_type; /* see ICMP message types above */ uint8_t dst[ETH_ALEN]; uint8_t orig[ETH_ALEN]; uint8_t uid; uint8_t align[3]; }; /** * batadv_icmp_packet - ICMP packet * @packet_type: batman-adv packet type, part of the general header * @version: batman-adv protocol version, part of the genereal header * @ttl: time to live for this packet, part of the genereal header * @msg_type: ICMP packet type * @dst: address of the destination node * @orig: address of the source node * @uid: local ICMP socket identifier * @reserved: not used - useful for alignment * @seqno: ICMP sequence number */ struct batadv_icmp_packet { uint8_t packet_type; uint8_t version; uint8_t ttl; uint8_t msg_type; /* see ICMP message types above */ uint8_t dst[ETH_ALEN]; uint8_t orig[ETH_ALEN]; uint8_t uid; uint8_t reserved; __be16 seqno; }; #define BATADV_RR_LEN 16 /** * batadv_icmp_packet_rr - ICMP RouteRecord packet * @packet_type: batman-adv packet type, part of the general header * @version: batman-adv protocol version, part of the genereal header * @ttl: time to live for this packet, part of the genereal header * @msg_type: ICMP packet type * @dst: address of the destination node * @orig: address of the source node * @uid: local ICMP socket identifier * @rr_cur: number of entries the rr array * @seqno: ICMP sequence number * @rr: route record array */ struct batadv_icmp_packet_rr { uint8_t packet_type; uint8_t version; uint8_t ttl; uint8_t msg_type; /* see ICMP message types above */ uint8_t dst[ETH_ALEN]; uint8_t orig[ETH_ALEN]; uint8_t uid; uint8_t rr_cur; __be16 seqno; uint8_t rr[BATADV_RR_LEN][ETH_ALEN]; }; #define BATADV_ICMP_MAX_PACKET_SIZE sizeof(struct batadv_icmp_packet_rr) /* All packet headers in front of an ethernet header have to be completely * divisible by 2 but not by 4 to make the payload after the ethernet * header again 4 bytes boundary aligned. * * A packing of 2 is necessary to avoid extra padding at the end of the struct * caused by a structure member which is larger than two bytes. Otherwise * the structure would not fulfill the previously mentioned rule to avoid the * misalignment of the payload after the ethernet header. It may also lead to * leakage of information when the padding it not initialized before sending. */ #pragma pack(2) /** * struct batadv_unicast_packet - unicast packet for network payload * @packet_type: batman-adv packet type, part of the general header * @version: batman-adv protocol version, part of the genereal header * @ttl: time to live for this packet, part of the genereal header * @ttvn: translation table version number * @dest: originator destination of the unicast packet */ struct batadv_unicast_packet { uint8_t packet_type; uint8_t version; uint8_t ttl; uint8_t ttvn; /* destination translation table version number */ uint8_t dest[ETH_ALEN]; /* "4 bytes boundary + 2 bytes" long to make the payload after the * following ethernet header again 4 bytes boundary aligned */ }; /** * struct batadv_unicast_4addr_packet - extended unicast packet * @u: common unicast packet header * @src: address of the source * @subtype: packet subtype */ struct batadv_unicast_4addr_packet { struct batadv_unicast_packet u; uint8_t src[ETH_ALEN]; uint8_t subtype; uint8_t reserved; /* "4 bytes boundary + 2 bytes" long to make the payload after the * following ethernet header again 4 bytes boundary aligned */ }; /** * struct batadv_frag_packet - fragmented packet * @packet_type: batman-adv packet type, part of the general header * @version: batman-adv protocol version, part of the genereal header * @ttl: time to live for this packet, part of the genereal header * @dest: final destination used when routing fragments * @orig: originator of the fragment used when merging the packet * @no: fragment number within this sequence * @reserved: reserved byte for alignment * @seqno: sequence identification * @total_size: size of the merged packet */ struct batadv_frag_packet { uint8_t packet_type; uint8_t version; /* batman version field */ uint8_t ttl; #if defined(__BIG_ENDIAN_BITFIELD) uint8_t no:4; uint8_t reserved:4; #elif defined(__LITTLE_ENDIAN_BITFIELD) uint8_t reserved:4; uint8_t no:4; #else #error "unknown bitfield endianess" #endif uint8_t dest[ETH_ALEN]; uint8_t orig[ETH_ALEN]; __be16 seqno; __be16 total_size; }; /** * struct batadv_bcast_packet - broadcast packet for network payload * @packet_type: batman-adv packet type, part of the general header * @version: batman-adv protocol version, part of the genereal header * @ttl: time to live for this packet, part of the genereal header * @reserved: reserved byte for alignment * @seqno: sequence identification * @orig: originator of the broadcast packet */ struct batadv_bcast_packet { uint8_t packet_type; uint8_t version; /* batman version field */ uint8_t ttl; uint8_t reserved; __be32 seqno; uint8_t orig[ETH_ALEN]; /* "4 bytes boundary + 2 bytes" long to make the payload after the * following ethernet header again 4 bytes boundary aligned */ }; /** * struct batadv_coded_packet - network coded packet * @packet_type: batman-adv packet type, part of the general header * @version: batman-adv protocol version, part of the genereal header * @ttl: time to live for this packet, part of the genereal header * @reserved: Align following fields to 2-byte boundaries * @first_source: original source of first included packet * @first_orig_dest: original destinal of first included packet * @first_crc: checksum of first included packet * @first_ttvn: tt-version number of first included packet * @second_ttl: ttl of second packet * @second_dest: second receiver of this coded packet * @second_source: original source of second included packet * @second_orig_dest: original destination of second included packet * @second_crc: checksum of second included packet * @second_ttvn: tt version number of second included packet * @coded_len: length of network coded part of the payload */ struct batadv_coded_packet { uint8_t packet_type; uint8_t version; /* batman version field */ uint8_t ttl; uint8_t first_ttvn; /* uint8_t first_dest[ETH_ALEN]; - saved in mac header destination */ uint8_t first_source[ETH_ALEN]; uint8_t first_orig_dest[ETH_ALEN]; __be32 first_crc; uint8_t second_ttl; uint8_t second_ttvn; uint8_t second_dest[ETH_ALEN]; uint8_t second_source[ETH_ALEN]; uint8_t second_orig_dest[ETH_ALEN]; __be32 second_crc; __be16 coded_len; }; #pragma pack() /** * struct batadv_unicast_tvlv - generic unicast packet with tvlv payload * @packet_type: batman-adv packet type, part of the general header * @version: batman-adv protocol version, part of the genereal header * @ttl: time to live for this packet, part of the genereal header * @reserved: reserved field (for packet alignment) * @src: address of the source * @dst: address of the destination * @tvlv_len: length of tvlv data following the unicast tvlv header * @align: 2 bytes to align the header to a 4 byte boundry */ struct batadv_unicast_tvlv_packet { uint8_t packet_type; uint8_t version; /* batman version field */ uint8_t ttl; uint8_t reserved; uint8_t dst[ETH_ALEN]; uint8_t src[ETH_ALEN]; __be16 tvlv_len; uint16_t align; }; /** * struct batadv_tvlv_hdr - base tvlv header struct * @type: tvlv container type (see batadv_tvlv_type) * @version: tvlv container version * @len: tvlv container length */ struct batadv_tvlv_hdr { uint8_t type; uint8_t version; __be16 len; }; /** * struct batadv_tvlv_gateway_data - gateway data propagated through gw tvlv * container * @bandwidth_down: advertised uplink download bandwidth * @bandwidth_up: advertised uplink upload bandwidth */ struct batadv_tvlv_gateway_data { __be32 bandwidth_down; __be32 bandwidth_up; }; /** * struct batadv_tvlv_tt_data - tt data propagated through the tt tvlv container * @flags: translation table flags (see batadv_tt_data_flags) * @ttvn: translation table version number * @vlan_num: number of announced VLANs. In the TVLV this struct is followed by * one batadv_tvlv_tt_vlan_data object per announced vlan */ struct batadv_tvlv_tt_data { uint8_t flags; uint8_t ttvn; __be16 num_vlan; }; /** * struct batadv_tvlv_tt_vlan_data - vlan specific tt data propagated through * the tt tvlv container * @crc: crc32 checksum of the entries belonging to this vlan * @vid: vlan identifier * @reserved: unused, useful for alignment purposes */ struct batadv_tvlv_tt_vlan_data { __be32 crc; __be16 vid; uint16_t reserved; }; /** * struct batadv_tvlv_tt_change - translation table diff data * @flags: status indicators concerning the non-mesh client (see * batadv_tt_client_flags) * @reserved: reserved field - useful for alignment purposes only * @addr: mac address of non-mesh client that triggered this tt change * @vid: VLAN identifier */ struct batadv_tvlv_tt_change { uint8_t flags; uint8_t reserved[3]; uint8_t addr[ETH_ALEN]; __be16 vid; }; /** * struct batadv_tvlv_roam_adv - roaming advertisement * @client: mac address of roaming client * @vid: VLAN identifier */ struct batadv_tvlv_roam_adv { uint8_t client[ETH_ALEN]; __be16 vid; }; #endif /* _NET_BATMAN_ADV_PACKET_H_ */ horst-4.2/batman_header.h000066400000000000000000000026321241274412600154470ustar00rootroot00000000000000/* 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 #include #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-4.2/capture-pcap.c000066400000000000000000000054771241274412600152660ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 #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; static 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, __attribute__((unused)) int recv_buffer_size) { char error[PCAP_ERRBUF_SIZE]; int ret; pcap_fp = pcap_create(devname, error); if (pcap_fp == NULL) { fprintf(stderr, "Couldn't create pcap: %s\n", error); return -1; } pcap_set_promisc(pcap_fp, 1); #if defined(__APPLE__) if (pcap_can_set_rfmon(pcap_fp)) pcap_set_rfmon(pcap_fp, 1); else err(1, "Couldn't activate monitor mode"); #endif ret = pcap_activate(pcap_fp); if (ret < 0) { fprintf(stderr, "Can't activate pcap: %d\n", ret); return -1; } return pcap_fileno(pcap_fp); } int device_get_hwinfo(__attribute__((unused)) int fd, __attribute__((unused)) char* ifname, __attribute__((unused)) unsigned char* mac) { 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; } } /* TODO: mac address not implemented */ return -1; } int recv_packet(__attribute__((unused)) 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(__attribute__((unused)) int fd, __attribute__((unused)) char* ifname) { if (pcap_fp != NULL) pcap_close(pcap_fp); } horst-4.2/capture.c000066400000000000000000000100321241274412600143240ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 #include "capture.h" #include "util.h" #include "main.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_hwinfo(int fd, char* ifname, unsigned char* mac) { 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); memcpy(mac, ifr.ifr_hwaddr.sa_data, 6); DEBUG("MY MAC %s\n", ether_sprintf(mac)); 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, 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) { printf("Could not create packet socket! Please run horst as root!\n"); exit(1); } /* 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-4.2/capture.h000066400000000000000000000022131241274412600143330ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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_ #include int open_packet_socket(char* devname, 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_hwinfo(int fd, char* ifname, unsigned char* mac); #endif // _CAPTURE_H_ horst-4.2/ccan/000077500000000000000000000000001241274412600134255ustar00rootroot00000000000000horst-4.2/ccan/build_assert/000077500000000000000000000000001241274412600161055ustar00rootroot00000000000000horst-4.2/ccan/build_assert/LICENSE000077700000000000000000000000001241274412600216302../../licenses/CC0ustar00rootroot00000000000000horst-4.2/ccan/build_assert/_info000066400000000000000000000025061241274412600171250ustar00rootroot00000000000000#include "config.h" #include #include /** * build_assert - routines for build-time assertions * * This code provides routines which will cause compilation to fail should some * assertion be untrue: such failures are preferable to run-time assertions, * but much more limited since they can only depends on compile-time constants. * * These assertions are most useful when two parts of the code must be kept in * sync: it is better to avoid such cases if possible, but seconds best is to * detect invalid changes at build time. * * For example, a tricky piece of code might rely on a certain element being at * the start of the structure. To ensure that future changes don't break it, * you would catch such changes in your code like so: * * Example: * #include * #include * * struct foo { * char string[5]; * int x; * }; * * static char *foo_string(struct foo *foo) * { * // This trick requires that the string be first in the structure * BUILD_ASSERT(offsetof(struct foo, string) == 0); * return (char *)foo; * } * * License: CC0 (Public domain) * Author: Rusty Russell */ int main(int argc, char *argv[]) { if (argc != 2) return 1; if (strcmp(argv[1], "depends") == 0) /* Nothing. */ return 0; return 1; } horst-4.2/ccan/build_assert/build_assert.h000066400000000000000000000023141241274412600207360ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */ #ifndef CCAN_BUILD_ASSERT_H #define CCAN_BUILD_ASSERT_H /** * BUILD_ASSERT - assert a build-time dependency. * @cond: the compile-time condition which must be true. * * Your compile will fail if the condition isn't true, or can't be evaluated * by the compiler. This can only be used within a function. * * Example: * #include * ... * static char *foo_to_char(struct foo *foo) * { * // This code needs string to be at start of foo. * BUILD_ASSERT(offsetof(struct foo, string) == 0); * return (char *)foo; * } */ #define BUILD_ASSERT(cond) \ do { (void) sizeof(char [1 - 2*!(cond)]); } while(0) /** * BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression. * @cond: the compile-time condition which must be true. * * Your compile will fail if the condition isn't true, or can't be evaluated * by the compiler. This can be used in an expression: its value is "0". * * Example: * #define foo_to_char(foo) \ * ((char *)(foo) \ * + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0)) */ #define BUILD_ASSERT_OR_ZERO(cond) \ (sizeof(char [1 - 2*!(cond)]) - 1) #endif /* CCAN_BUILD_ASSERT_H */ horst-4.2/ccan/build_assert/test/000077500000000000000000000000001241274412600170645ustar00rootroot00000000000000horst-4.2/ccan/build_assert/test/compile_fail-expr.c000066400000000000000000000002341241274412600226260ustar00rootroot00000000000000#include int main(int argc, char *argv[]) { #ifdef FAIL return BUILD_ASSERT_OR_ZERO(1 == 0); #else return 0; #endif } horst-4.2/ccan/build_assert/test/compile_fail.c000066400000000000000000000002071241274412600216520ustar00rootroot00000000000000#include int main(int argc, char *argv[]) { #ifdef FAIL BUILD_ASSERT(1 == 0); #endif return 0; } horst-4.2/ccan/build_assert/test/compile_ok.c000066400000000000000000000001641241274412600213520ustar00rootroot00000000000000#include int main(int argc, char *argv[]) { BUILD_ASSERT(1 == 1); return 0; } horst-4.2/ccan/build_assert/test/run-BUILD_ASSERT_OR_ZERO.c000066400000000000000000000002741241274412600232140ustar00rootroot00000000000000#include #include int main(int argc, char *argv[]) { plan_tests(1); ok1(BUILD_ASSERT_OR_ZERO(1 == 1) == 0); return exit_status(); } horst-4.2/ccan/check_type/000077500000000000000000000000001241274412600155435ustar00rootroot00000000000000horst-4.2/ccan/check_type/LICENSE000077700000000000000000000000001241274412600212662../../licenses/CC0ustar00rootroot00000000000000horst-4.2/ccan/check_type/_info000066400000000000000000000015111241274412600165560ustar00rootroot00000000000000#include "config.h" #include #include /** * check_type - routines for compile time type checking * * C has fairly weak typing: ints get automatically converted to longs, signed * to unsigned, etc. There are some cases where this is best avoided, and * these macros provide methods for evoking warnings (or build errors) when * a precise type isn't used. * * On compilers which don't support typeof() these routines are less effective, * since they have to use sizeof() which can only distiguish between types of * different size. * * License: CC0 (Public domain) * Author: Rusty Russell */ int main(int argc, char *argv[]) { if (argc != 2) return 1; if (strcmp(argv[1], "depends") == 0) { #if !HAVE_TYPEOF printf("ccan/build_assert\n"); #endif return 0; } return 1; } horst-4.2/ccan/check_type/check_type.h000066400000000000000000000045051241274412600200360ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */ #ifndef CCAN_CHECK_TYPE_H #define CCAN_CHECK_TYPE_H #include "config.h" /** * check_type - issue a warning or build failure if type is not correct. * @expr: the expression whose type we should check (not evaluated). * @type: the exact type we expect the expression to be. * * This macro is usually used within other macros to try to ensure that a macro * argument is of the expected type. No type promotion of the expression is * done: an unsigned int is not the same as an int! * * check_type() always evaluates to 0. * * If your compiler does not support typeof, then the best we can do is fail * to compile if the sizes of the types are unequal (a less complete check). * * Example: * // They should always pass a 64-bit value to _set_some_value! * #define set_some_value(expr) \ * _set_some_value((check_type((expr), uint64_t), (expr))) */ /** * check_types_match - issue a warning or build failure if types are not same. * @expr1: the first expression (not evaluated). * @expr2: the second expression (not evaluated). * * This macro is usually used within other macros to try to ensure that * arguments are of identical types. No type promotion of the expressions is * done: an unsigned int is not the same as an int! * * check_types_match() always evaluates to 0. * * If your compiler does not support typeof, then the best we can do is fail * to compile if the sizes of the types are unequal (a less complete check). * * Example: * // Do subtraction to get to enclosing type, but make sure that * // pointer is of correct type for that member. * #define container_of(mbr_ptr, encl_type, mbr) \ * (check_types_match((mbr_ptr), &((encl_type *)0)->mbr), \ * ((encl_type *) \ * ((char *)(mbr_ptr) - offsetof(enclosing_type, mbr)))) */ #if HAVE_TYPEOF #define check_type(expr, type) \ ((typeof(expr) *)0 != (type *)0) #define check_types_match(expr1, expr2) \ ((typeof(expr1) *)0 != (typeof(expr2) *)0) #else #include /* Without typeof, we can only test the sizes. */ #define check_type(expr, type) \ BUILD_ASSERT_OR_ZERO(sizeof(expr) == sizeof(type)) #define check_types_match(expr1, expr2) \ BUILD_ASSERT_OR_ZERO(sizeof(expr1) == sizeof(expr2)) #endif /* HAVE_TYPEOF */ #endif /* CCAN_CHECK_TYPE_H */ horst-4.2/ccan/check_type/test/000077500000000000000000000000001241274412600165225ustar00rootroot00000000000000horst-4.2/ccan/check_type/test/compile_fail-check_type.c000066400000000000000000000002051241274412600234220ustar00rootroot00000000000000#include int main(int argc, char *argv[]) { #ifdef FAIL check_type(argc, char); #endif return 0; } horst-4.2/ccan/check_type/test/compile_fail-check_type_unsigned.c000066400000000000000000000003751241274412600253260ustar00rootroot00000000000000#include int main(int argc, char *argv[]) { #ifdef FAIL #if HAVE_TYPEOF check_type(argc, unsigned int); #else /* This doesn't work without typeof, so just fail */ #error "Fail without typeof" #endif #endif return 0; } horst-4.2/ccan/check_type/test/compile_fail-check_types_match.c000066400000000000000000000002421241274412600247620ustar00rootroot00000000000000#include int main(int argc, char *argv[]) { unsigned char x = argc; #ifdef FAIL check_types_match(argc, x); #endif return x; } horst-4.2/ccan/check_type/test/run.c000066400000000000000000000010621241274412600174710ustar00rootroot00000000000000#include #include int main(int argc, char *argv[]) { int x = 0, y = 0; plan_tests(9); ok1(check_type(argc, int) == 0); ok1(check_type(&argc, int *) == 0); ok1(check_types_match(argc, argc) == 0); ok1(check_types_match(argc, x) == 0); ok1(check_types_match(&argc, &x) == 0); ok1(check_type(x++, int) == 0); ok(x == 0, "check_type does not evaluate expression"); ok1(check_types_match(x++, y++) == 0); ok(x == 0 && y == 0, "check_types_match does not evaluate expressions"); return exit_status(); } horst-4.2/ccan/container_of/000077500000000000000000000000001241274412600160735ustar00rootroot00000000000000horst-4.2/ccan/container_of/LICENSE000077700000000000000000000000001241274412600216162../../licenses/CC0ustar00rootroot00000000000000horst-4.2/ccan/container_of/_info000066400000000000000000000024741241274412600171170ustar00rootroot00000000000000#include "config.h" #include #include /** * container_of - routine for upcasting * * It is often convenient to create code where the caller registers a pointer * to a generic structure and a callback. The callback might know that the * pointer points to within a larger structure, and container_of gives a * convenient and fairly type-safe way of returning to the enclosing structure. * * This idiom is an alternative to providing a void * pointer for every * callback. * * Example: * #include * #include * * struct timer { * void *members; * }; * * struct info { * int my_stuff; * struct timer timer; * }; * * static void register_timer(struct timer *timer) * { * //... * } * * static void my_timer_callback(struct timer *timer) * { * struct info *info = container_of(timer, struct info, timer); * printf("my_stuff is %u\n", info->my_stuff); * } * * int main(void) * { * struct info info = { .my_stuff = 1 }; * * register_timer(&info.timer); * // ... * return 0; * } * * License: CC0 (Public domain) * Author: Rusty Russell */ int main(int argc, char *argv[]) { if (argc != 2) return 1; if (strcmp(argv[1], "depends") == 0) { printf("ccan/check_type\n"); return 0; } return 1; } horst-4.2/ccan/container_of/container_of.h000066400000000000000000000061341241274412600207160ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */ #ifndef CCAN_CONTAINER_OF_H #define CCAN_CONTAINER_OF_H #include #include "config.h" #include /** * container_of - get pointer to enclosing structure * @member_ptr: pointer to the structure member * @containing_type: the type this member is within * @member: the name of this member within the structure. * * Given a pointer to a member of a structure, this macro does pointer * subtraction to return the pointer to the enclosing type. * * Example: * struct foo { * int fielda, fieldb; * // ... * }; * struct info { * int some_other_field; * struct foo my_foo; * }; * * static struct info *foo_to_info(struct foo *foo) * { * return container_of(foo, struct info, my_foo); * } */ #define container_of(member_ptr, containing_type, member) \ ((containing_type *) \ ((char *)(member_ptr) \ - container_off(containing_type, member)) \ + check_types_match(*(member_ptr), ((containing_type *)0)->member)) /** * container_off - get offset to enclosing structure * @containing_type: the type this member is within * @member: the name of this member within the structure. * * Given a pointer to a member of a structure, this macro does * typechecking and figures out the offset to the enclosing type. * * Example: * struct foo { * int fielda, fieldb; * // ... * }; * struct info { * int some_other_field; * struct foo my_foo; * }; * * static struct info *foo_to_info(struct foo *foo) * { * size_t off = container_off(struct info, my_foo); * return (void *)((char *)foo - off); * } */ #define container_off(containing_type, member) \ offsetof(containing_type, member) /** * container_of_var - get pointer to enclosing structure using a variable * @member_ptr: pointer to the structure member * @container_var: a pointer of same type as this member's container * @member: the name of this member within the structure. * * Given a pointer to a member of a structure, this macro does pointer * subtraction to return the pointer to the enclosing type. * * Example: * static struct info *foo_to_i(struct foo *foo) * { * struct info *i = container_of_var(foo, i, my_foo); * return i; * } */ #if HAVE_TYPEOF #define container_of_var(member_ptr, container_var, member) \ container_of(member_ptr, typeof(*container_var), member) #else #define container_of_var(member_ptr, container_var, member) \ ((void *)((char *)(member_ptr) - \ container_off_var(container_var, member))) #endif /** * container_off_var - get offset of a field in enclosing structure * @container_var: a pointer to a container structure * @member: the name of a member within the structure. * * Given (any) pointer to a structure and a its member name, this * macro does pointer subtraction to return offset of member in a * structure memory layout. * */ #if HAVE_TYPEOF #define container_off_var(var, member) \ container_off(typeof(*var), member) #else #define container_off_var(var, member) \ ((const char *)&(var)->member - (const char *)(var)) #endif #endif /* CCAN_CONTAINER_OF_H */ horst-4.2/ccan/container_of/test/000077500000000000000000000000001241274412600170525ustar00rootroot00000000000000horst-4.2/ccan/container_of/test/compile_fail-bad-type.c000066400000000000000000000005511241274412600233450ustar00rootroot00000000000000#include #include struct foo { int a; char b; }; int main(int argc, char *argv[]) { struct foo foo = { .a = 1, .b = 2 }; int *intp = &foo.a; char *p; #ifdef FAIL /* p is a char *, but this gives a struct foo * */ p = container_of(intp, struct foo, a); #else p = (char *)intp; #endif return p == NULL; } horst-4.2/ccan/container_of/test/compile_fail-types.c000066400000000000000000000006321241274412600230040ustar00rootroot00000000000000#include #include struct foo { int a; char b; }; int main(int argc, char *argv[]) { struct foo foo = { .a = 1, .b = 2 }, *foop; int *intp = &foo.a; #ifdef FAIL /* b is a char, but intp is an int * */ foop = container_of(intp, struct foo, b); #else foop = NULL; #endif (void) foop; /* Suppress unused-but-set-variable warning. */ return intp == NULL; } horst-4.2/ccan/container_of/test/compile_fail-var-types.c000066400000000000000000000007561241274412600236010ustar00rootroot00000000000000#include #include struct foo { int a; char b; }; int main(int argc, char *argv[]) { struct foo foo = { .a = 1, .b = 2 }, *foop; int *intp = &foo.a; #ifdef FAIL /* b is a char, but intp is an int * */ foop = container_of_var(intp, foop, b); #if !HAVE_TYPEOF #error "Unfortunately we don't fail if we don't have typeof." #endif #else foop = NULL; #endif (void) foop; /* Suppress unused-but-set-variable warning. */ return intp == NULL; } horst-4.2/ccan/container_of/test/run.c000066400000000000000000000012271241274412600200240ustar00rootroot00000000000000#include #include struct foo { int a; char b; }; int main(int argc, char *argv[]) { struct foo foo = { .a = 1, .b = 2 }; int *intp = &foo.a; char *charp = &foo.b; plan_tests(8); ok1(container_of(intp, struct foo, a) == &foo); ok1(container_of(charp, struct foo, b) == &foo); ok1(container_of_var(intp, &foo, a) == &foo); ok1(container_of_var(charp, &foo, b) == &foo); ok1(container_off(struct foo, a) == 0); ok1(container_off(struct foo, b) == offsetof(struct foo, b)); ok1(container_off_var(&foo, a) == 0); ok1(container_off_var(&foo, b) == offsetof(struct foo, b)); return exit_status(); } horst-4.2/ccan/list/000077500000000000000000000000001241274412600144005ustar00rootroot00000000000000horst-4.2/ccan/list/LICENSE000077700000000000000000000000001241274412600206152../../licenses/BSD-MITustar00rootroot00000000000000horst-4.2/ccan/list/_info000066400000000000000000000027701241274412600154230ustar00rootroot00000000000000#include "config.h" #include #include /** * list - double linked list routines * * The list header contains routines for manipulating double linked lists. * It defines two types: struct list_head used for anchoring lists, and * struct list_node which is usually embedded in the structure which is placed * in the list. * * Example: * #include * #include * #include * #include * * struct parent { * const char *name; * struct list_head children; * unsigned int num_children; * }; * * struct child { * const char *name; * struct list_node list; * }; * * int main(int argc, char *argv[]) * { * struct parent p; * struct child *c; * unsigned int i; * * if (argc < 2) * errx(1, "Usage: %s parent children...", argv[0]); * * p.name = argv[1]; * list_head_init(&p.children); * p.num_children = 0; * for (i = 2; i < argc; i++) { * c = malloc(sizeof(*c)); * c->name = argv[i]; * list_add(&p.children, &c->list); * p.num_children++; * } * * printf("%s has %u children:", p.name, p.num_children); * list_for_each(&p.children, c, list) * printf("%s ", c->name); * printf("\n"); * return 0; * } * * License: BSD-MIT * Author: Rusty Russell */ int main(int argc, char *argv[]) { if (argc != 2) return 1; if (strcmp(argv[1], "depends") == 0) { printf("ccan/str\n"); printf("ccan/container_of\n"); printf("ccan/check_type\n"); return 0; } return 1; } horst-4.2/ccan/list/list.c000066400000000000000000000017501241274412600155220ustar00rootroot00000000000000/* Licensed under BSD-MIT - see LICENSE file for details */ #include #include #include "list.h" static void *corrupt(const char *abortstr, const struct list_node *head, const struct list_node *node, unsigned int count) { if (abortstr) { fprintf(stderr, "%s: prev corrupt in node %p (%u) of %p\n", abortstr, node, count, head); abort(); } return NULL; } struct list_node *list_check_node(const struct list_node *node, const char *abortstr) { const struct list_node *p, *n; int count = 0; for (p = node, n = node->next; n != node; p = n, n = n->next) { count++; if (n->prev != p) return corrupt(abortstr, node, n, count); } /* Check prev on head node. */ if (node->prev != p) return corrupt(abortstr, node, node, 0); return (struct list_node *)node; } struct list_head *list_check(const struct list_head *h, const char *abortstr) { if (!list_check_node(&h->n, abortstr)) return NULL; return (struct list_head *)h; } horst-4.2/ccan/list/list.h000066400000000000000000000451371241274412600155360ustar00rootroot00000000000000/* Licensed under BSD-MIT - see LICENSE file for details */ #ifndef CCAN_LIST_H #define CCAN_LIST_H //#define CCAN_LIST_DEBUG 1 #include #include #include #include #include /** * struct list_node - an entry in a doubly-linked list * @next: next entry (self if empty) * @prev: previous entry (self if empty) * * This is used as an entry in a linked list. * Example: * struct child { * const char *name; * // Linked list of all us children. * struct list_node list; * }; */ struct list_node { struct list_node *next, *prev; }; /** * struct list_head - the head of a doubly-linked list * @h: the list_head (containing next and prev pointers) * * This is used as the head of a linked list. * Example: * struct parent { * const char *name; * struct list_head children; * unsigned int num_children; * }; */ struct list_head { struct list_node n; }; /** * list_check - check head of a list for consistency * @h: the list_head * @abortstr: the location to print on aborting, or NULL. * * Because list_nodes have redundant information, consistency checking between * the back and forward links can be done. This is useful as a debugging check. * If @abortstr is non-NULL, that will be printed in a diagnostic if the list * is inconsistent, and the function will abort. * * Returns the list head if the list is consistent, NULL if not (it * can never return NULL if @abortstr is set). * * See also: list_check_node() * * Example: * static void dump_parent(struct parent *p) * { * struct child *c; * * printf("%s (%u children):\n", p->name, p->num_children); * list_check(&p->children, "bad child list"); * list_for_each(&p->children, c, list) * printf(" -> %s\n", c->name); * } */ struct list_head *list_check(const struct list_head *h, const char *abortstr); /** * list_check_node - check node of a list for consistency * @n: the list_node * @abortstr: the location to print on aborting, or NULL. * * Check consistency of the list node is in (it must be in one). * * See also: list_check() * * Example: * static void dump_child(const struct child *c) * { * list_check_node(&c->list, "bad child list"); * printf("%s\n", c->name); * } */ struct list_node *list_check_node(const struct list_node *n, const char *abortstr); #define LIST_LOC __FILE__ ":" stringify(__LINE__) #ifdef CCAN_LIST_DEBUG #define list_debug(h, loc) list_check((h), loc) #define list_debug_node(n, loc) list_check_node((n), loc) #else #define list_debug(h, loc) (h) #define list_debug_node(n, loc) (n) #endif /** * LIST_HEAD_INIT - initializer for an empty list_head * @name: the name of the list. * * Explicit initializer for an empty list. * * See also: * LIST_HEAD, list_head_init() * * Example: * static struct list_head my_list = LIST_HEAD_INIT(my_list); */ #define LIST_HEAD_INIT(name) { { &name.n, &name.n } } /** * LIST_HEAD - define and initialize an empty list_head * @name: the name of the list. * * The LIST_HEAD macro defines a list_head and initializes it to an empty * list. It can be prepended by "static" to define a static list_head. * * See also: * LIST_HEAD_INIT, list_head_init() * * Example: * static LIST_HEAD(my_global_list); */ #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name) /** * list_head_init - initialize a list_head * @h: the list_head to set to the empty list * * Example: * ... * struct parent *parent = malloc(sizeof(*parent)); * * list_head_init(&parent->children); * parent->num_children = 0; */ static inline void list_head_init(struct list_head *h) { h->n.next = h->n.prev = &h->n; } /** * list_add - add an entry at the start of a linked list. * @h: the list_head to add the node to * @n: the list_node to add to the list. * * The list_node does not need to be initialized; it will be overwritten. * Example: * struct child *child = malloc(sizeof(*child)); * * child->name = "marvin"; * list_add(&parent->children, &child->list); * parent->num_children++; */ #define list_add(h, n) list_add_(h, n, LIST_LOC) static inline void list_add_(struct list_head *h, struct list_node *n, __attribute__((unused)) const char *abortstr) { n->next = h->n.next; n->prev = &h->n; h->n.next->prev = n; h->n.next = n; (void)list_debug(h, abortstr); } /** * list_add_tail - add an entry at the end of a linked list. * @h: the list_head to add the node to * @n: the list_node to add to the list. * * The list_node does not need to be initialized; it will be overwritten. * Example: * list_add_tail(&parent->children, &child->list); * parent->num_children++; */ #define list_add_tail(h, n) list_add_tail_(h, n, LIST_LOC) static inline void list_add_tail_(struct list_head *h, struct list_node *n, __attribute__((unused)) const char *abortstr) { n->next = &h->n; n->prev = h->n.prev; h->n.prev->next = n; h->n.prev = n; (void)list_debug(h, abortstr); } /** * list_empty - is a list empty? * @h: the list_head * * If the list is empty, returns true. * * Example: * assert(list_empty(&parent->children) == (parent->num_children == 0)); */ #define list_empty(h) list_empty_(h, LIST_LOC) static inline bool list_empty_(const struct list_head *h, __attribute__((unused)) const char* abortstr) { (void)list_debug(h, abortstr); return h->n.next == &h->n; } /** * list_empty_nodebug - is a list empty (and don't perform debug checks)? * @h: the list_head * * If the list is empty, returns true. * This differs from list_empty() in that if CCAN_LIST_DEBUG is set it * will NOT perform debug checks. Only use this function if you REALLY * know what you're doing. * * Example: * assert(list_empty_nodebug(&parent->children) == (parent->num_children == 0)); */ #ifndef CCAN_LIST_DEBUG #define list_empty_nodebug(h) list_empty(h) #else static inline bool list_empty_nodebug(const struct list_head *h) { return h->n.next == &h->n; } #endif /** * list_del - delete an entry from an (unknown) linked list. * @n: the list_node to delete from the list. * * Note that this leaves @n in an undefined state; it can be added to * another list, but not deleted again. * * See also: * list_del_from() * * Example: * list_del(&child->list); * parent->num_children--; */ #define list_del(n) list_del_(n, LIST_LOC) static inline void list_del_(struct list_node *n, __attribute__((unused)) const char* abortstr) { (void)list_debug_node(n, abortstr); n->next->prev = n->prev; n->prev->next = n->next; #ifdef CCAN_LIST_DEBUG /* Catch use-after-del. */ n->next = n->prev = NULL; #endif } /** * list_del_from - delete an entry from a known linked list. * @h: the list_head the node is in. * @n: the list_node to delete from the list. * * This explicitly indicates which list a node is expected to be in, * which is better documentation and can catch more bugs. * * See also: list_del() * * Example: * list_del_from(&parent->children, &child->list); * parent->num_children--; */ static inline void list_del_from(struct list_head *h, struct list_node *n) { #ifdef CCAN_LIST_DEBUG { /* Thorough check: make sure it was in list! */ struct list_node *i; for (i = h->n.next; i != n; i = i->next) assert(i != &h->n); } #endif /* CCAN_LIST_DEBUG */ /* Quick test that catches a surprising number of bugs. */ assert(!list_empty(h)); list_del(n); } /** * list_entry - convert a list_node back into the structure containing it. * @n: the list_node * @type: the type of the entry * @member: the list_node member of the type * * Example: * // First list entry is children.next; convert back to child. * child = list_entry(parent->children.n.next, struct child, list); * * See Also: * list_top(), list_for_each() */ #define list_entry(n, type, member) container_of(n, type, member) /** * list_top - get the first entry in a list * @h: the list_head * @type: the type of the entry * @member: the list_node member of the type * * If the list is empty, returns NULL. * * Example: * struct child *first; * first = list_top(&parent->children, struct child, list); * if (!first) * printf("Empty list!\n"); */ #define list_top(h, type, member) \ ((type *)list_top_((h), list_off_(type, member))) static inline const void *list_top_(const struct list_head *h, size_t off) { if (list_empty(h)) return NULL; return (const char *)h->n.next - off; } /** * list_pop - remove the first entry in a list * @h: the list_head * @type: the type of the entry * @member: the list_node member of the type * * If the list is empty, returns NULL. * * Example: * struct child *one; * one = list_pop(&parent->children, struct child, list); * if (!one) * printf("Empty list!\n"); */ #define list_pop(h, type, member) \ ((type *)list_pop_((h), list_off_(type, member))) static inline const void *list_pop_(const struct list_head *h, size_t off) { struct list_node *n; if (list_empty(h)) return NULL; n = h->n.next; list_del(n); return (const char *)n - off; } /** * list_tail - get the last entry in a list * @h: the list_head * @type: the type of the entry * @member: the list_node member of the type * * If the list is empty, returns NULL. * * Example: * struct child *last; * last = list_tail(&parent->children, struct child, list); * if (!last) * printf("Empty list!\n"); */ #define list_tail(h, type, member) \ ((type *)list_tail_((h), list_off_(type, member))) static inline const void *list_tail_(const struct list_head *h, size_t off) { if (list_empty(h)) return NULL; return (const char *)h->n.prev - off; } /** * list_for_each - iterate through a list. * @h: the list_head (warning: evaluated multiple times!) * @i: the structure containing the list_node * @member: the list_node member of the structure * * This is a convenient wrapper to iterate @i over the entire list. It's * a for loop, so you can break and continue as normal. * * Example: * list_for_each(&parent->children, child, list) * printf("Name: %s\n", child->name); */ #define list_for_each(h, i, member) \ list_for_each_off(h, i, list_off_var_(i, member)) /** * list_for_each_rev - iterate through a list backwards. * @h: the list_head * @i: the structure containing the list_node * @member: the list_node member of the structure * * This is a convenient wrapper to iterate @i over the entire list. It's * a for loop, so you can break and continue as normal. * * Example: * list_for_each_rev(&parent->children, child, list) * printf("Name: %s\n", child->name); */ #define list_for_each_rev(h, i, member) \ for (i = container_of_var(list_debug(h, LIST_LOC)->n.prev, i, member); \ &i->member != &(h)->n; \ i = container_of_var(i->member.prev, i, member)) /** * list_for_each_safe - iterate through a list, maybe during deletion * @h: the list_head * @i: the structure containing the list_node * @nxt: the structure containing the list_node * @member: the list_node member of the structure * * This is a convenient wrapper to iterate @i over the entire list. It's * a for loop, so you can break and continue as normal. The extra variable * @nxt is used to hold the next element, so you can delete @i from the list. * * Example: * struct child *next; * list_for_each_safe(&parent->children, child, next, list) { * list_del(&child->list); * parent->num_children--; * } */ #define list_for_each_safe(h, i, nxt, member) \ list_for_each_safe_off(h, i, nxt, list_off_var_(i, member)) /** * list_next - get the next entry in a list * @h: the list_head * @i: a pointer to an entry in the list. * @member: the list_node member of the structure * * If @i was the last entry in the list, returns NULL. * * Example: * struct child *second; * second = list_next(&parent->children, first, list); * if (!second) * printf("No second child!\n"); */ #define list_next(h, i, member) \ ((list_typeof(i))list_entry_or_null(list_debug(h, \ __FILE__ ":" stringify(__LINE__)), \ (i)->member.next, \ list_off_var_((i), member))) /** * list_prev - get the previous entry in a list * @h: the list_head * @i: a pointer to an entry in the list. * @member: the list_node member of the structure * * If @i was the first entry in the list, returns NULL. * * Example: * first = list_prev(&parent->children, second, list); * if (!first) * printf("Can't go back to first child?!\n"); */ #define list_prev(h, i, member) \ ((list_typeof(i))list_entry_or_null(list_debug(h, \ __FILE__ ":" stringify(__LINE__)), \ (i)->member.prev, \ list_off_var_((i), member))) /** * list_append_list - empty one list onto the end of another. * @to: the list to append into * @from: the list to empty. * * This takes the entire contents of @from and moves it to the end of * @to. After this @from will be empty. * * Example: * struct list_head adopter; * * list_append_list(&adopter, &parent->children); * assert(list_empty(&parent->children)); * parent->num_children = 0; */ #define list_append_list(t, f) list_append_list_(t, f, \ __FILE__ ":" stringify(__LINE__)) static inline void list_append_list_(struct list_head *to, struct list_head *from, __attribute__((unused)) const char *abortstr) { struct list_node *from_tail = list_debug(from, abortstr)->n.prev; struct list_node *to_tail = list_debug(to, abortstr)->n.prev; /* Sew in head and entire list. */ to->n.prev = from_tail; from_tail->next = &to->n; to_tail->next = &from->n; from->n.prev = to_tail; /* Now remove head. */ list_del(&from->n); list_head_init(from); } /** * list_prepend_list - empty one list into the start of another. * @to: the list to prepend into * @from: the list to empty. * * This takes the entire contents of @from and moves it to the start * of @to. After this @from will be empty. * * Example: * list_prepend_list(&adopter, &parent->children); * assert(list_empty(&parent->children)); * parent->num_children = 0; */ #define list_prepend_list(t, f) list_prepend_list_(t, f, LIST_LOC) static inline void list_prepend_list_(struct list_head *to, struct list_head *from, __attribute__((unused)) const char *abortstr) { struct list_node *from_tail = list_debug(from, abortstr)->n.prev; struct list_node *to_head = list_debug(to, abortstr)->n.next; /* Sew in head and entire list. */ to->n.next = &from->n; from->n.prev = &to->n; to_head->prev = from_tail; from_tail->next = to_head; /* Now remove head. */ list_del(&from->n); list_head_init(from); } /** * list_for_each_off - iterate through a list of memory regions. * @h: the list_head * @i: the pointer to a memory region wich contains list node data. * @off: offset(relative to @i) at which list node data resides. * * This is a low-level wrapper to iterate @i over the entire list, used to * implement all oher, more high-level, for-each constructs. It's a for loop, * so you can break and continue as normal. * * WARNING! Being the low-level macro that it is, this wrapper doesn't know * nor care about the type of @i. The only assumtion made is that @i points * to a chunk of memory that at some @offset, relative to @i, contains a * properly filled `struct node_list' which in turn contains pointers to * memory chunks and it's turtles all the way down. Whith all that in mind * remember that given the wrong pointer/offset couple this macro will * happilly churn all you memory untill SEGFAULT stops it, in other words * caveat emptor. * * It is worth mentioning that one of legitimate use-cases for that wrapper * is operation on opaque types with known offset for `struct list_node' * member(preferably 0), because it allows you not to disclose the type of * @i. * * Example: * list_for_each_off(&parent->children, child, * offsetof(struct child, list)) * printf("Name: %s\n", child->name); */ #define list_for_each_off(h, i, off) \ for (i = list_node_to_off_(list_debug(h, LIST_LOC)->n.next, \ (off)); \ list_node_from_off_((void *)i, (off)) != &(h)->n; \ i = list_node_to_off_(list_node_from_off_((void *)i, (off))->next, \ (off))) /** * list_for_each_safe_off - iterate through a list of memory regions, maybe * during deletion * @h: the list_head * @i: the pointer to a memory region wich contains list node data. * @nxt: the structure containing the list_node * @off: offset(relative to @i) at which list node data resides. * * For details see `list_for_each_off' and `list_for_each_safe' * descriptions. * * Example: * list_for_each_safe_off(&parent->children, child, * next, offsetof(struct child, list)) * printf("Name: %s\n", child->name); */ #define list_for_each_safe_off(h, i, nxt, off) \ for (i = list_node_to_off_(list_debug(h, LIST_LOC)->n.next, \ (off)), \ nxt = list_node_to_off_(list_node_from_off_(i, (off))->next, \ (off)); \ list_node_from_off_(i, (off)) != &(h)->n; \ i = nxt, \ nxt = list_node_to_off_(list_node_from_off_(i, (off))->next, \ (off))) /* Other -off variants. */ #define list_entry_off(n, type, off) \ ((type *)list_node_from_off_((n), (off))) #define list_head_off(h, type, off) \ ((type *)list_head_off((h), (off))) #define list_tail_off(h, type, off) \ ((type *)list_tail_((h), (off))) #define list_add_off(h, n, off) \ list_add((h), list_node_from_off_((n), (off))) #define list_del_off(n, off) \ list_del(list_node_from_off_((n), (off))) #define list_del_from_off(h, n, off) \ list_del_from(h, list_node_from_off_((n), (off))) /* Offset helper functions so we only single-evaluate. */ static inline void *list_node_to_off_(struct list_node *node, size_t off) { return (void *)((char *)node - off); } static inline struct list_node *list_node_from_off_(void *ptr, size_t off) { return (struct list_node *)((char *)ptr + off); } /* Get the offset of the member, but make sure it's a list_node. */ #define list_off_(type, member) \ (container_off(type, member) + \ check_type(((type *)0)->member, struct list_node)) #define list_off_var_(var, member) \ (container_off_var(var, member) + \ check_type(var->member, struct list_node)) #if HAVE_TYPEOF #define list_typeof(var) typeof(var) #else #define list_typeof(var) void * #endif /* Returns member, or NULL if at end of list. */ static inline void *list_entry_or_null(const struct list_head *h, const struct list_node *n, size_t off) { if (n == &h->n) return NULL; return (char *)n - off; } #endif /* CCAN_LIST_H */ horst-4.2/ccan/list/test/000077500000000000000000000000001241274412600153575ustar00rootroot00000000000000horst-4.2/ccan/list/test/compile_ok-constant.c000066400000000000000000000015641241274412600215010ustar00rootroot00000000000000#include #include #include #include #include struct child { const char *name; struct list_node list; }; static bool children(const struct list_head *list) { return !list_empty(list); } static const struct child *first_child(const struct list_head *list) { return list_top(list, struct child, list); } static const struct child *last_child(const struct list_head *list) { return list_tail(list, struct child, list); } static void check_children(const struct list_head *list) { list_check(list, "bad child list"); } static void print_children(const struct list_head *list) { const struct child *c; list_for_each(list, c, list) printf("%s\n", c->name); } int main(void) { LIST_HEAD(h); children(&h); first_child(&h); last_child(&h); check_children(&h); print_children(&h); return 0; } horst-4.2/ccan/list/test/helper.c000066400000000000000000000024261241274412600170060ustar00rootroot00000000000000#include #include #include #include #include "helper.h" #define ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING \ (42) struct opaque { struct list_node list; size_t secret_offset; char secret_drawer[42]; }; static bool not_randomized = true; struct opaque *create_opaque_blob(void) { struct opaque *blob = calloc(1, sizeof(struct opaque)); if (not_randomized) { srandom((int)time(NULL)); not_randomized = false; } blob->secret_offset = random() % (sizeof(blob->secret_drawer)); blob->secret_drawer[blob->secret_offset] = ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING; return blob; } bool if_blobs_know_the_secret(struct opaque *blob) { bool answer = true; int i; for (i = 0; i < sizeof(blob->secret_drawer) / sizeof(blob->secret_drawer[0]); i++) if (i != blob->secret_offset) answer = answer && (blob->secret_drawer[i] == 0); else answer = answer && (blob->secret_drawer[blob->secret_offset] == ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING); return answer; } void destroy_opaque_blob(struct opaque *blob) { free(blob); } horst-4.2/ccan/list/test/helper.h000066400000000000000000000003711241274412600170100ustar00rootroot00000000000000/* These are in a separate C file so we can test undefined structures. */ struct opaque; typedef struct opaque opaque_t; opaque_t *create_opaque_blob(void); bool if_blobs_know_the_secret(opaque_t *blob); void destroy_opaque_blob(opaque_t *blob); horst-4.2/ccan/list/test/run-CCAN_LIST_DEBUG.c000066400000000000000000000024441241274412600205760ustar00rootroot00000000000000/* Check that CCAN_LIST_DEBUG works */ #include #include #include #include #include #include /* We don't actually want it to exit... */ static jmp_buf aborted; #define abort() longjmp(aborted, 1) #define fprintf my_fprintf static char printf_buffer[1000]; static int my_fprintf(FILE *stream, const char *format, ...) { va_list ap; int ret; va_start(ap, format); ret = vsprintf(printf_buffer, format, ap); va_end(ap); return ret; } #define CCAN_LIST_DEBUG 1 #include #include #include int main(int argc, char *argv[]) { struct list_head list; struct list_node n1; char expect[100]; plan_tests(2); /* Empty list. */ list.n.next = &list.n; list.n.prev = &list.n; ok1(list_check(&list, NULL) == &list); /* Bad back ptr */ list.n.prev = &n1; /* Aborting version. */ sprintf(expect, "run-CCAN_LIST_DEBUG.c:50: prev corrupt in node %p (0) of %p\n", &list, &list); if (setjmp(aborted) == 0) { assert(list_empty(&list)); fail("list_empty on empty with bad back ptr didn't fail!"); } else { /* __FILE__ might give full path. */ int prep = strlen(printf_buffer) - strlen(expect); ok1(prep >= 0 && strcmp(printf_buffer + prep, expect) == 0); } return exit_status(); } horst-4.2/ccan/list/test/run-check-corrupt.c000066400000000000000000000040111241274412600210720ustar00rootroot00000000000000#include #include #include #include #include #include /* We don't actually want it to exit... */ static jmp_buf aborted; #define abort() longjmp(aborted, 1) #define fprintf my_fprintf static char printf_buffer[1000]; static int my_fprintf(FILE *stream, const char *format, ...) { va_list ap; int ret; va_start(ap, format); ret = vsprintf(printf_buffer, format, ap); va_end(ap); return ret; } #include #include #include int main(int argc, char *argv[]) { struct list_head list; struct list_node n1; char expect[100]; plan_tests(9); /* Empty list. */ list.n.next = &list.n; list.n.prev = &list.n; ok1(list_check(&list, NULL) == &list); /* Bad back ptr */ list.n.prev = &n1; /* Non-aborting version. */ ok1(list_check(&list, NULL) == NULL); /* Aborting version. */ sprintf(expect, "test message: prev corrupt in node %p (0) of %p\n", &list, &list); if (setjmp(aborted) == 0) { list_check(&list, "test message"); fail("list_check on empty with bad back ptr didn't fail!"); } else { ok1(strcmp(printf_buffer, expect) == 0); } /* n1 in list. */ list.n.next = &n1; list.n.prev = &n1; n1.prev = &list.n; n1.next = &list.n; ok1(list_check(&list, NULL) == &list); ok1(list_check_node(&n1, NULL) == &n1); /* Bad back ptr */ n1.prev = &n1; ok1(list_check(&list, NULL) == NULL); ok1(list_check_node(&n1, NULL) == NULL); /* Aborting version. */ sprintf(expect, "test message: prev corrupt in node %p (1) of %p\n", &n1, &list); if (setjmp(aborted) == 0) { list_check(&list, "test message"); fail("list_check on n1 bad back ptr didn't fail!"); } else { ok1(strcmp(printf_buffer, expect) == 0); } sprintf(expect, "test message: prev corrupt in node %p (0) of %p\n", &n1, &n1); if (setjmp(aborted) == 0) { list_check_node(&n1, "test message"); fail("list_check_node on n1 bad back ptr didn't fail!"); } else { ok1(strcmp(printf_buffer, expect) == 0); } return exit_status(); } horst-4.2/ccan/list/test/run-check-nonconst.c000066400000000000000000000012101241274412600212330ustar00rootroot00000000000000#include #include #include #include "helper.h" struct child { const char *name; struct list_node list; }; int main(int argc, char *argv[]) { struct child c1, c2; struct list_head list = LIST_HEAD_INIT(list); plan_tests(1); list_add(&list, &c1.list); list_add_tail(list_check(&list, "Bad list!"), &c2.list); list_del_from(list_check(&list, "Bad list!"), list_check_node(&c2.list, "Bad node!")); list_del_from(list_check(&list, "Bad list!"), list_check_node(&c1.list, "Bad node!")); ok1(list_empty(list_check(&list, "Bad emptied list"))); return exit_status(); } horst-4.2/ccan/list/test/run-list_del_from-assert.c000066400000000000000000000013011241274412600224410ustar00rootroot00000000000000#define CCAN_LIST_DEBUG 1 #include #include #include #include #include #include #include int main(int argc, char *argv[]) { struct list_head list1, list2; struct list_node n1, n2, n3; pid_t child; int status; plan_tests(1); list_head_init(&list1); list_head_init(&list2); list_add(&list1, &n1); list_add(&list2, &n2); list_add_tail(&list2, &n3); child = fork(); if (child) { wait(&status); } else { /* This should abort. */ list_del_from(&list1, &n3); exit(0); } ok1(WIFSIGNALED(status) && WTERMSIG(status) == SIGABRT); list_del_from(&list2, &n3); return exit_status(); } horst-4.2/ccan/list/test/run-list_prev-list_next.c000066400000000000000000000033451241274412600223500ustar00rootroot00000000000000#include #include #include #include "helper.h" struct parent { const char *name; unsigned int num_children; struct list_head children; }; struct child { const char *name; struct list_node list; }; int main(int argc, char *argv[]) { struct parent parent; struct child c1, c2, c3; const struct parent *p; const struct child *c; plan_tests(20); parent.num_children = 0; list_head_init(&parent.children); c1.name = "c1"; list_add(&parent.children, &c1.list); ok1(list_next(&parent.children, &c1, list) == NULL); ok1(list_prev(&parent.children, &c1, list) == NULL); c2.name = "c2"; list_add_tail(&parent.children, &c2.list); ok1(list_next(&parent.children, &c1, list) == &c2); ok1(list_prev(&parent.children, &c1, list) == NULL); ok1(list_next(&parent.children, &c2, list) == NULL); ok1(list_prev(&parent.children, &c2, list) == &c1); c3.name = "c3"; list_add_tail(&parent.children, &c3.list); ok1(list_next(&parent.children, &c1, list) == &c2); ok1(list_prev(&parent.children, &c1, list) == NULL); ok1(list_next(&parent.children, &c2, list) == &c3); ok1(list_prev(&parent.children, &c2, list) == &c1); ok1(list_next(&parent.children, &c3, list) == NULL); ok1(list_prev(&parent.children, &c3, list) == &c2); /* Const variants */ p = &parent; c = &c2; ok1(list_next(&p->children, &c1, list) == &c2); ok1(list_prev(&p->children, &c1, list) == NULL); ok1(list_next(&p->children, c, list) == &c3); ok1(list_prev(&p->children, c, list) == &c1); ok1(list_next(&parent.children, c, list) == &c3); ok1(list_prev(&parent.children, c, list) == &c1); ok1(list_next(&p->children, &c3, list) == NULL); ok1(list_prev(&p->children, &c3, list) == &c2); return exit_status(); } horst-4.2/ccan/list/test/run-prepend_list.c000066400000000000000000000053761241274412600210300ustar00rootroot00000000000000#include #include #include #include static bool list_expect(struct list_head *h, ...) { va_list ap; struct list_node *n = &h->n, *expected; va_start(ap, h); while ((expected = va_arg(ap, struct list_node *)) != NULL) { n = n->next; if (n != expected) return false; } return (n->next == &h->n); } int main(int argc, char *argv[]) { struct list_head h1, h2; struct list_node n[4]; plan_tests(40); list_head_init(&h1); list_head_init(&h2); /* Append an empty list to an empty list. */ list_append_list(&h1, &h2); ok1(list_empty(&h1)); ok1(list_empty(&h2)); ok1(list_check(&h1, NULL)); ok1(list_check(&h2, NULL)); /* Prepend an empty list to an empty list. */ list_prepend_list(&h1, &h2); ok1(list_empty(&h1)); ok1(list_empty(&h2)); ok1(list_check(&h1, NULL)); ok1(list_check(&h2, NULL)); /* Append an empty list to a non-empty list */ list_add(&h1, &n[0]); list_append_list(&h1, &h2); ok1(list_empty(&h2)); ok1(list_check(&h1, NULL)); ok1(list_check(&h2, NULL)); ok1(list_expect(&h1, &n[0], NULL)); /* Prepend an empty list to a non-empty list */ list_prepend_list(&h1, &h2); ok1(list_empty(&h2)); ok1(list_check(&h1, NULL)); ok1(list_check(&h2, NULL)); ok1(list_expect(&h1, &n[0], NULL)); /* Append a non-empty list to an empty list. */ list_append_list(&h2, &h1); ok1(list_empty(&h1)); ok1(list_check(&h1, NULL)); ok1(list_check(&h2, NULL)); ok1(list_expect(&h2, &n[0], NULL)); /* Prepend a non-empty list to an empty list. */ list_prepend_list(&h1, &h2); ok1(list_empty(&h2)); ok1(list_check(&h1, NULL)); ok1(list_check(&h2, NULL)); ok1(list_expect(&h1, &n[0], NULL)); /* Prepend a non-empty list to non-empty list. */ list_add(&h2, &n[1]); list_prepend_list(&h1, &h2); ok1(list_empty(&h2)); ok1(list_check(&h1, NULL)); ok1(list_check(&h2, NULL)); ok1(list_expect(&h1, &n[1], &n[0], NULL)); /* Append a non-empty list to non-empty list. */ list_add(&h2, &n[2]); list_append_list(&h1, &h2); ok1(list_empty(&h2)); ok1(list_check(&h1, NULL)); ok1(list_check(&h2, NULL)); ok1(list_expect(&h1, &n[1], &n[0], &n[2], NULL)); /* Prepend a 2-entry list to a 2-entry list. */ list_del_from(&h1, &n[2]); list_add(&h2, &n[2]); list_add_tail(&h2, &n[3]); list_prepend_list(&h1, &h2); ok1(list_empty(&h2)); ok1(list_check(&h1, NULL)); ok1(list_check(&h2, NULL)); ok1(list_expect(&h1, &n[2], &n[3], &n[1], &n[0], NULL)); /* Append a 2-entry list to a 2-entry list. */ list_del_from(&h1, &n[2]); list_del_from(&h1, &n[3]); list_add(&h2, &n[2]); list_add_tail(&h2, &n[3]); list_append_list(&h1, &h2); ok1(list_empty(&h2)); ok1(list_check(&h1, NULL)); ok1(list_check(&h2, NULL)); ok1(list_expect(&h1, &n[1], &n[0], &n[2], &n[3], NULL)); return exit_status(); } horst-4.2/ccan/list/test/run-single-eval.c000066400000000000000000000111511241274412600205320ustar00rootroot00000000000000/* Make sure macros only evaluate their args once. */ #include #include #include struct parent { const char *name; struct list_head children; unsigned int num_children; int eval_count; }; struct child { const char *name; struct list_node list; }; static LIST_HEAD(static_list); #define ref(obj, counter) ((counter)++, (obj)) int main(int argc, char *argv[]) { struct parent parent; struct child c1, c2, c3, *c, *n; unsigned int i; unsigned int static_count = 0, parent_count = 0, list_count = 0, node_count = 0; struct list_head list = LIST_HEAD_INIT(list); plan_tests(74); /* Test LIST_HEAD, LIST_HEAD_INIT, list_empty and check_list */ ok1(list_empty(ref(&static_list, static_count))); ok1(static_count == 1); ok1(list_check(ref(&static_list, static_count), NULL)); ok1(static_count == 2); ok1(list_empty(ref(&list, list_count))); ok1(list_count == 1); ok1(list_check(ref(&list, list_count), NULL)); ok1(list_count == 2); parent.num_children = 0; list_head_init(ref(&parent.children, parent_count)); ok1(parent_count == 1); /* Test list_head_init */ ok1(list_empty(ref(&parent.children, parent_count))); ok1(parent_count == 2); ok1(list_check(ref(&parent.children, parent_count), NULL)); ok1(parent_count == 3); c2.name = "c2"; list_add(ref(&parent.children, parent_count), &c2.list); ok1(parent_count == 4); /* Test list_add and !list_empty. */ ok1(!list_empty(ref(&parent.children, parent_count))); ok1(parent_count == 5); ok1(c2.list.next == &parent.children.n); ok1(c2.list.prev == &parent.children.n); ok1(parent.children.n.next == &c2.list); ok1(parent.children.n.prev == &c2.list); /* Test list_check */ ok1(list_check(ref(&parent.children, parent_count), NULL)); ok1(parent_count == 6); c1.name = "c1"; list_add(ref(&parent.children, parent_count), &c1.list); ok1(parent_count == 7); /* Test list_add and !list_empty. */ ok1(!list_empty(ref(&parent.children, parent_count))); ok1(parent_count == 8); ok1(c2.list.next == &parent.children.n); ok1(c2.list.prev == &c1.list); ok1(parent.children.n.next == &c1.list); ok1(parent.children.n.prev == &c2.list); ok1(c1.list.next == &c2.list); ok1(c1.list.prev == &parent.children.n); /* Test list_check */ ok1(list_check(ref(&parent.children, parent_count), NULL)); ok1(parent_count == 9); c3.name = "c3"; list_add_tail(ref(&parent.children, parent_count), &c3.list); ok1(parent_count == 10); /* Test list_add_tail and !list_empty. */ ok1(!list_empty(ref(&parent.children, parent_count))); ok1(parent_count == 11); ok1(parent.children.n.next == &c1.list); ok1(parent.children.n.prev == &c3.list); ok1(c1.list.next == &c2.list); ok1(c1.list.prev == &parent.children.n); ok1(c2.list.next == &c3.list); ok1(c2.list.prev == &c1.list); ok1(c3.list.next == &parent.children.n); ok1(c3.list.prev == &c2.list); /* Test list_check */ ok1(list_check(ref(&parent.children, parent_count), NULL)); ok1(parent_count == 12); /* Test list_check_node */ ok1(list_check_node(&c1.list, NULL)); ok1(list_check_node(&c2.list, NULL)); ok1(list_check_node(&c3.list, NULL)); /* Test list_top */ ok1(list_top(ref(&parent.children, parent_count), struct child, list) == &c1); ok1(parent_count == 13); /* Test list_tail */ ok1(list_tail(ref(&parent.children, parent_count), struct child, list) == &c3); ok1(parent_count == 14); /* Test list_for_each. */ i = 0; list_for_each(&parent.children, c, list) { switch (i++) { case 0: ok1(c == &c1); break; case 1: ok1(c == &c2); break; case 2: ok1(c == &c3); break; } if (i > 2) break; } ok1(i == 3); /* Test list_for_each_safe, list_del and list_del_from. */ i = 0; list_for_each_safe(&parent.children, c, n, list) { switch (i++) { case 0: ok1(c == &c1); list_del(ref(&c->list, node_count)); ok1(node_count == 1); break; case 1: ok1(c == &c2); list_del_from(ref(&parent.children, parent_count), ref(&c->list, node_count)); ok1(node_count == 2); break; case 2: ok1(c == &c3); list_del_from(ref(&parent.children, parent_count), ref(&c->list, node_count)); ok1(node_count == 3); break; } ok1(list_check(ref(&parent.children, parent_count), NULL)); if (i > 2) break; } ok1(i == 3); ok1(parent_count == 19); ok1(list_empty(ref(&parent.children, parent_count))); ok1(parent_count == 20); /* Test list_top/list_tail on empty list. */ ok1(list_top(ref(&parent.children, parent_count), struct child, list) == NULL); ok1(parent_count == 21); ok1(list_tail(ref(&parent.children, parent_count), struct child, list) == NULL); ok1(parent_count == 22); return exit_status(); } horst-4.2/ccan/list/test/run-with-debug.c000066400000000000000000000001641241274412600203650ustar00rootroot00000000000000/* Just like run.c, but with all debug checks enabled. */ #define CCAN_LIST_DEBUG 1 #include horst-4.2/ccan/list/test/run.c000066400000000000000000000115431241274412600163330ustar00rootroot00000000000000#include #include #include #include "helper.h" struct parent { const char *name; struct list_head children; unsigned int num_children; }; struct child { const char *name; struct list_node list; }; static LIST_HEAD(static_list); int main(int argc, char *argv[]) { struct parent parent; struct child c1, c2, c3, *c, *n; unsigned int i; struct list_head list = LIST_HEAD_INIT(list); opaque_t *q, *nq; struct list_head opaque_list = LIST_HEAD_INIT(opaque_list); plan_tests(68); /* Test LIST_HEAD, LIST_HEAD_INIT, list_empty and check_list */ ok1(list_empty(&static_list)); ok1(list_check(&static_list, NULL)); ok1(list_empty(&list)); ok1(list_check(&list, NULL)); parent.num_children = 0; list_head_init(&parent.children); /* Test list_head_init */ ok1(list_empty(&parent.children)); ok1(list_check(&parent.children, NULL)); c2.name = "c2"; list_add(&parent.children, &c2.list); /* Test list_add and !list_empty. */ ok1(!list_empty(&parent.children)); ok1(c2.list.next == &parent.children.n); ok1(c2.list.prev == &parent.children.n); ok1(parent.children.n.next == &c2.list); ok1(parent.children.n.prev == &c2.list); /* Test list_check */ ok1(list_check(&parent.children, NULL)); c1.name = "c1"; list_add(&parent.children, &c1.list); /* Test list_add and !list_empty. */ ok1(!list_empty(&parent.children)); ok1(c2.list.next == &parent.children.n); ok1(c2.list.prev == &c1.list); ok1(parent.children.n.next == &c1.list); ok1(parent.children.n.prev == &c2.list); ok1(c1.list.next == &c2.list); ok1(c1.list.prev == &parent.children.n); /* Test list_check */ ok1(list_check(&parent.children, NULL)); c3.name = "c3"; list_add_tail(&parent.children, &c3.list); /* Test list_add_tail and !list_empty. */ ok1(!list_empty(&parent.children)); ok1(parent.children.n.next == &c1.list); ok1(parent.children.n.prev == &c3.list); ok1(c1.list.next == &c2.list); ok1(c1.list.prev == &parent.children.n); ok1(c2.list.next == &c3.list); ok1(c2.list.prev == &c1.list); ok1(c3.list.next == &parent.children.n); ok1(c3.list.prev == &c2.list); /* Test list_check */ ok1(list_check(&parent.children, NULL)); /* Test list_check_node */ ok1(list_check_node(&c1.list, NULL)); ok1(list_check_node(&c2.list, NULL)); ok1(list_check_node(&c3.list, NULL)); /* Test list_top */ ok1(list_top(&parent.children, struct child, list) == &c1); /* Test list_pop */ ok1(list_pop(&parent.children, struct child, list) == &c1); ok1(list_top(&parent.children, struct child, list) == &c2); list_add(&parent.children, &c1.list); /* Test list_tail */ ok1(list_tail(&parent.children, struct child, list) == &c3); /* Test list_for_each. */ i = 0; list_for_each(&parent.children, c, list) { switch (i++) { case 0: ok1(c == &c1); break; case 1: ok1(c == &c2); break; case 2: ok1(c == &c3); break; } if (i > 2) break; } ok1(i == 3); /* Test list_for_each_rev. */ i = 0; list_for_each_rev(&parent.children, c, list) { switch (i++) { case 0: ok1(c == &c3); break; case 1: ok1(c == &c2); break; case 2: ok1(c == &c1); break; } if (i > 2) break; } ok1(i == 3); /* Test list_for_each_safe, list_del and list_del_from. */ i = 0; list_for_each_safe(&parent.children, c, n, list) { switch (i++) { case 0: ok1(c == &c1); list_del(&c->list); break; case 1: ok1(c == &c2); list_del_from(&parent.children, &c->list); break; case 2: ok1(c == &c3); list_del_from(&parent.children, &c->list); break; } ok1(list_check(&parent.children, NULL)); if (i > 2) break; } ok1(i == 3); ok1(list_empty(&parent.children)); /* Test list_for_each_off. */ list_add_tail(&opaque_list, (struct list_node *)create_opaque_blob()); list_add_tail(&opaque_list, (struct list_node *)create_opaque_blob()); list_add_tail(&opaque_list, (struct list_node *)create_opaque_blob()); i = 0; list_for_each_off(&opaque_list, q, 0) { i++; ok1(if_blobs_know_the_secret(q)); } ok1(i == 3); /* Test list_for_each_safe_off, list_del_off and list_del_from_off. */ i = 0; list_for_each_safe_off(&opaque_list, q, nq, 0) { switch (i++) { case 0: ok1(if_blobs_know_the_secret(q)); list_del_off(q, 0); destroy_opaque_blob(q); break; case 1: ok1(if_blobs_know_the_secret(q)); list_del_from_off(&opaque_list, q, 0); destroy_opaque_blob(q); break; case 2: ok1(c == &c3); list_del_from_off(&opaque_list, q, 0); destroy_opaque_blob(q); break; } ok1(list_check(&opaque_list, NULL)); if (i > 2) break; } ok1(i == 3); ok1(list_empty(&opaque_list)); /* Test list_top/list_tail/list_pop on empty list. */ ok1(list_top(&parent.children, struct child, list) == NULL); ok1(list_tail(&parent.children, struct child, list) == NULL); ok1(list_pop(&parent.children, struct child, list) == NULL); return exit_status(); } horst-4.2/ccan/str/000077500000000000000000000000001241274412600142355ustar00rootroot00000000000000horst-4.2/ccan/str/LICENSE000077700000000000000000000000001241274412600177602../../licenses/CC0ustar00rootroot00000000000000horst-4.2/ccan/str/_info000066400000000000000000000025101241274412600152500ustar00rootroot00000000000000#include "config.h" #include #include /** * str - string helper routines * * This is a grab bag of functions for string operations, designed to enhance * the standard string.h. * * Note that if you define CCAN_STR_DEBUG, you will get extra compile * checks on common misuses of the following functions (they will now * be out-of-line, so there is a runtime penalty!). * * strstr, strchr, strrchr: * Return const char * if first argument is const (gcc only). * * isalnum, isalpha, isascii, isblank, iscntrl, isdigit, isgraph, * islower, isprint, ispunct, isspace, isupper, isxdigit: * Static and runtime check that input is EOF or an *unsigned* * char, as per C standard (really!). * * Example: * #include * #include * * int main(int argc, char *argv[]) * { * if (argv[1] && streq(argv[1], "--verbose")) * printf("verbose set\n"); * if (argv[1] && strstarts(argv[1], "--")) * printf("Some option set\n"); * if (argv[1] && strends(argv[1], "cow-powers")) * printf("Magic option set\n"); * return 0; * } * * License: CC0 (Public domain) * Author: Rusty Russell */ int main(int argc, char *argv[]) { if (argc != 2) return 1; if (strcmp(argv[1], "depends") == 0) { printf("ccan/build_assert\n"); return 0; } return 1; } horst-4.2/ccan/str/debug.c000066400000000000000000000031021241274412600154630ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */ #include "config.h" #include #include #include #include #ifdef CCAN_STR_DEBUG /* Because we mug the real ones with macros, we need our own wrappers. */ int str_isalnum(int i) { assert(i >= -1 && i < 256); return isalnum(i); } int str_isalpha(int i) { assert(i >= -1 && i < 256); return isalpha(i); } int str_isascii(int i) { assert(i >= -1 && i < 256); return isascii(i); } #if HAVE_ISBLANK int str_isblank(int i) { assert(i >= -1 && i < 256); return isblank(i); } #endif int str_iscntrl(int i) { assert(i >= -1 && i < 256); return iscntrl(i); } int str_isdigit(int i) { assert(i >= -1 && i < 256); return isdigit(i); } int str_isgraph(int i) { assert(i >= -1 && i < 256); return isgraph(i); } int str_islower(int i) { assert(i >= -1 && i < 256); return islower(i); } int str_isprint(int i) { assert(i >= -1 && i < 256); return isprint(i); } int str_ispunct(int i) { assert(i >= -1 && i < 256); return ispunct(i); } int str_isspace(int i) { assert(i >= -1 && i < 256); return isspace(i); } int str_isupper(int i) { assert(i >= -1 && i < 256); return isupper(i); } int str_isxdigit(int i) { assert(i >= -1 && i < 256); return isxdigit(i); } #undef strstr #undef strchr #undef strrchr char *str_strstr(const char *haystack, const char *needle) { return strstr(haystack, needle); } char *str_strchr(const char *haystack, int c) { return strchr(haystack, c); } char *str_strrchr(const char *haystack, int c) { return strrchr(haystack, c); } #endif horst-4.2/ccan/str/str.c000066400000000000000000000004331241274412600152110ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */ #include size_t strcount(const char *haystack, const char *needle) { size_t i = 0, nlen = strlen(needle); while ((haystack = strstr(haystack, needle)) != NULL) { i++; haystack += nlen; } return i; } horst-4.2/ccan/str/str.h000066400000000000000000000135031241274412600152200ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */ #ifndef CCAN_STR_H #define CCAN_STR_H #include "config.h" #include #include #include #include /** * streq - Are two strings equal? * @a: first string * @b: first string * * This macro is arguably more readable than "!strcmp(a, b)". * * Example: * if (streq(somestring, "")) * printf("String is empty!\n"); */ #define streq(a,b) (strcmp((a),(b)) == 0) /** * strstarts - Does this string start with this prefix? * @str: string to test * @prefix: prefix to look for at start of str * * Example: * if (strstarts(somestring, "foo")) * printf("String %s begins with 'foo'!\n", somestring); */ #define strstarts(str,prefix) (strncmp((str),(prefix),strlen(prefix)) == 0) /** * strends - Does this string end with this postfix? * @str: string to test * @postfix: postfix to look for at end of str * * Example: * if (strends(somestring, "foo")) * printf("String %s end with 'foo'!\n", somestring); */ static inline bool strends(const char *str, const char *postfix) { if (strlen(str) < strlen(postfix)) return false; return streq(str + strlen(str) - strlen(postfix), postfix); } /** * stringify - Turn expression into a string literal * @expr: any C expression * * Example: * #define PRINT_COND_IF_FALSE(cond) \ * ((cond) || printf("%s is false!", stringify(cond))) */ #define stringify(expr) stringify_1(expr) /* Double-indirection required to stringify expansions */ #define stringify_1(expr) #expr /** * strcount - Count number of (non-overlapping) occurrences of a substring. * @haystack: a C string * @needle: a substring * * Example: * assert(strcount("aaa aaa", "a") == 6); * assert(strcount("aaa aaa", "ab") == 0); * assert(strcount("aaa aaa", "aa") == 2); */ size_t strcount(const char *haystack, const char *needle); /** * STR_MAX_CHARS - Maximum possible size of numeric string for this type. * @type_or_expr: a pointer or integer type or expression. * * This provides enough space for a nul-terminated string which represents the * largest possible value for the type or expression. * * Note: The implementation adds extra space so hex values or negative * values will fit (eg. sprintf(... "%p"). ) * * Example: * char str[STR_MAX_CHARS(int)]; * * sprintf(str, "%i", 7); */ #define STR_MAX_CHARS(type_or_expr) \ ((sizeof(type_or_expr) * CHAR_BIT + 8) / 9 * 3 + 2 \ + STR_MAX_CHARS_TCHECK_(type_or_expr)) #if HAVE_TYPEOF /* Only a simple type can have 0 assigned, so test that. */ #define STR_MAX_CHARS_TCHECK_(type_or_expr) \ ({ typeof(type_or_expr) x = 0; (void)x; 0; }) #else #define STR_MAX_CHARS_TCHECK_(type_or_expr) 0 #endif /** * cisalnum - isalnum() which takes a char (and doesn't accept EOF) * @c: a character * * Surprisingly, the standard ctype.h isalnum() takes an int, which * must have the value of EOF (-1) or an unsigned char. This variant * takes a real char, and doesn't accept EOF. */ static inline bool cisalnum(char c) { return isalnum((unsigned char)c); } static inline bool cisalpha(char c) { return isalpha((unsigned char)c); } static inline bool cisascii(char c) { return isascii((unsigned char)c); } #if HAVE_ISBLANK static inline bool cisblank(char c) { return isblank((unsigned char)c); } #endif static inline bool ciscntrl(char c) { return iscntrl((unsigned char)c); } static inline bool cisdigit(char c) { return isdigit((unsigned char)c); } static inline bool cisgraph(char c) { return isgraph((unsigned char)c); } static inline bool cislower(char c) { return islower((unsigned char)c); } static inline bool cisprint(char c) { return isprint((unsigned char)c); } static inline bool cispunct(char c) { return ispunct((unsigned char)c); } static inline bool cisspace(char c) { return isspace((unsigned char)c); } static inline bool cisupper(char c) { return isupper((unsigned char)c); } static inline bool cisxdigit(char c) { return isxdigit((unsigned char)c); } #include /* These checks force things out of line, hence they are under DEBUG. */ #ifdef CCAN_STR_DEBUG #include /* These are commonly misused: they take -1 or an *unsigned* char value. */ #undef isalnum #undef isalpha #undef isascii #undef isblank #undef iscntrl #undef isdigit #undef isgraph #undef islower #undef isprint #undef ispunct #undef isspace #undef isupper #undef isxdigit /* You can use a char if char is unsigned. */ #if HAVE_BUILTIN_TYPES_COMPATIBLE_P && HAVE_TYPEOF #define str_check_arg_(i) \ ((i) + BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(typeof(i), \ char) \ || (char)255 > 0)) #else #define str_check_arg_(i) (i) #endif #define isalnum(i) str_isalnum(str_check_arg_(i)) #define isalpha(i) str_isalpha(str_check_arg_(i)) #define isascii(i) str_isascii(str_check_arg_(i)) #if HAVE_ISBLANK #define isblank(i) str_isblank(str_check_arg_(i)) #endif #define iscntrl(i) str_iscntrl(str_check_arg_(i)) #define isdigit(i) str_isdigit(str_check_arg_(i)) #define isgraph(i) str_isgraph(str_check_arg_(i)) #define islower(i) str_islower(str_check_arg_(i)) #define isprint(i) str_isprint(str_check_arg_(i)) #define ispunct(i) str_ispunct(str_check_arg_(i)) #define isspace(i) str_isspace(str_check_arg_(i)) #define isupper(i) str_isupper(str_check_arg_(i)) #define isxdigit(i) str_isxdigit(str_check_arg_(i)) #if HAVE_TYPEOF /* With GNU magic, we can make const-respecting standard string functions. */ #undef strstr #undef strchr #undef strrchr /* + 0 is needed to decay array into pointer. */ #define strstr(haystack, needle) \ ((typeof((haystack) + 0))str_strstr((haystack), (needle))) #define strchr(haystack, c) \ ((typeof((haystack) + 0))str_strchr((haystack), (c))) #define strrchr(haystack, c) \ ((typeof((haystack) + 0))str_strrchr((haystack), (c))) #endif #endif /* CCAN_STR_DEBUG */ #endif /* CCAN_STR_H */ horst-4.2/ccan/str/str_debug.h000066400000000000000000000014061241274412600163650ustar00rootroot00000000000000/* CC0 (Public domain) - see LICENSE file for details */ #ifndef CCAN_STR_DEBUG_H #define CCAN_STR_DEBUG_H /* #define CCAN_STR_DEBUG 1 */ #ifdef CCAN_STR_DEBUG /* Because we mug the real ones with macros, we need our own wrappers. */ int str_isalnum(int i); int str_isalpha(int i); int str_isascii(int i); #if HAVE_ISBLANK int str_isblank(int i); #endif int str_iscntrl(int i); int str_isdigit(int i); int str_isgraph(int i); int str_islower(int i); int str_isprint(int i); int str_ispunct(int i); int str_isspace(int i); int str_isupper(int i); int str_isxdigit(int i); char *str_strstr(const char *haystack, const char *needle); char *str_strchr(const char *s, int c); char *str_strrchr(const char *s, int c); #endif /* CCAN_STR_DEBUG */ #endif /* CCAN_STR_DEBUG_H */ horst-4.2/ccan/str/test/000077500000000000000000000000001241274412600152145ustar00rootroot00000000000000horst-4.2/ccan/str/test/compile_fail-STR_MAX_CHARS.c000066400000000000000000000004561241274412600221030ustar00rootroot00000000000000#include struct s { int val; }; int main(int argc, char *argv[]) { struct s #ifdef FAIL #if !HAVE_TYPEOF #error We need typeof to check STR_MAX_CHARS. #endif #else /* A pointer is OK. */ * #endif val; char str[STR_MAX_CHARS(val)]; str[0] = '\0'; return str[0] ? 0 : 1; } horst-4.2/ccan/str/test/compile_fail-isalnum.c000066400000000000000000000005611241274412600214530ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check isalnum. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return isalnum(c); } horst-4.2/ccan/str/test/compile_fail-isalpha.c000066400000000000000000000005611241274412600214240ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check isalpha. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return isalpha(c); } horst-4.2/ccan/str/test/compile_fail-isascii.c000066400000000000000000000005611241274412600214270ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check isascii. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return isascii(c); } horst-4.2/ccan/str/test/compile_fail-isblank.c000066400000000000000000000006531241274412600214300ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF || !HAVE_ISBLANK #error We need typeof to check isblank. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif #if HAVE_ISBLANK return isblank(c); #else return c; #endif } horst-4.2/ccan/str/test/compile_fail-iscntrl.c000066400000000000000000000005611241274412600214610ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check iscntrl. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return iscntrl(c); } horst-4.2/ccan/str/test/compile_fail-isdigit.c000066400000000000000000000005611241274412600214370ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check isdigit. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return isdigit(c); } horst-4.2/ccan/str/test/compile_fail-islower.c000066400000000000000000000005611241274412600214670ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check islower. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return islower(c); } horst-4.2/ccan/str/test/compile_fail-isprint.c000066400000000000000000000005611241274412600214730ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check isprint. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return isprint(c); } horst-4.2/ccan/str/test/compile_fail-ispunct.c000066400000000000000000000005611241274412600214700ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check ispunct. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return ispunct(c); } horst-4.2/ccan/str/test/compile_fail-isspace.c000066400000000000000000000005611241274412600214320ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check isspace. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return isspace(c); } horst-4.2/ccan/str/test/compile_fail-isupper.c000066400000000000000000000005611241274412600214720ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check isupper. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return isupper(c); } horst-4.2/ccan/str/test/compile_fail-isxdigit.c000066400000000000000000000005631241274412600216310ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_BUILTIN_TYPES_COMPATIBLE_P || !HAVE_TYPEOF #error We need typeof to check isxdigit. #endif char #else unsigned char #endif c = argv[0][0]; #ifdef FAIL /* Fake fail on unsigned char platforms. */ BUILD_ASSERT((char)255 < 0); #endif return isxdigit(c); } horst-4.2/ccan/str/test/compile_fail-strchr.c000066400000000000000000000004211241274412600213030ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_TYPEOF #error We need typeof to check strstr. #endif #else const #endif char *ret; const char *str = "hello"; ret = strchr(str, 'l'); return ret ? 0 : 1; } horst-4.2/ccan/str/test/compile_fail-strrchr.c000066400000000000000000000004221241274412600214660ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_TYPEOF #error We need typeof to check strstr. #endif #else const #endif char *ret; const char *str = "hello"; ret = strrchr(str, 'l'); return ret ? 0 : 1; } horst-4.2/ccan/str/test/compile_fail-strstr.c000066400000000000000000000004241241274412600213420ustar00rootroot00000000000000#define CCAN_STR_DEBUG 1 #include int main(int argc, char *argv[]) { #ifdef FAIL #if !HAVE_TYPEOF #error We need typeof to check strstr. #endif #else const #endif char *ret; const char *str = "hello"; ret = strstr(str, "hell"); return ret ? 0 : 1; } horst-4.2/ccan/str/test/debug.c000066400000000000000000000003241241274412600164450ustar00rootroot00000000000000/* We can't use the normal "#include the .c file" trick, since this is contaminated by str.h's macro overrides. So we put it in all tests like this. */ #define CCAN_STR_DEBUG 1 #include horst-4.2/ccan/str/test/run-STR_MAX_CHARS.c000066400000000000000000000032661241274412600202660ustar00rootroot00000000000000#include #include #include #include #include int main(int argc, char *argv[]) { char str[1000]; struct { uint8_t u1byte; int8_t s1byte; uint16_t u2byte; int16_t s2byte; uint32_t u4byte; int32_t s4byte; uint64_t u8byte; int64_t s8byte; void *ptr; } types; plan_tests(13); memset(&types, 0xFF, sizeof(types)); /* Hex versions */ sprintf(str, "0x%llx", (unsigned long long)types.u1byte); ok1(strlen(str) < STR_MAX_CHARS(types.u1byte)); sprintf(str, "0x%llx", (unsigned long long)types.u2byte); ok1(strlen(str) < STR_MAX_CHARS(types.u2byte)); sprintf(str, "0x%llx", (unsigned long long)types.u4byte); ok1(strlen(str) < STR_MAX_CHARS(types.u4byte)); sprintf(str, "0x%llx", (unsigned long long)types.u8byte); ok1(strlen(str) < STR_MAX_CHARS(types.u8byte)); /* Decimal versions */ sprintf(str, "%u", types.u1byte); ok1(strlen(str) < STR_MAX_CHARS(types.u1byte)); sprintf(str, "%d", types.s1byte); ok1(strlen(str) < STR_MAX_CHARS(types.s1byte)); sprintf(str, "%u", types.u2byte); ok1(strlen(str) < STR_MAX_CHARS(types.u2byte)); sprintf(str, "%d", types.s2byte); ok1(strlen(str) < STR_MAX_CHARS(types.s2byte)); sprintf(str, "%u", types.u4byte); ok1(strlen(str) < STR_MAX_CHARS(types.u4byte)); sprintf(str, "%d", types.s4byte); ok1(strlen(str) < STR_MAX_CHARS(types.s4byte)); sprintf(str, "%llu", (unsigned long long)types.u8byte); ok1(strlen(str) < STR_MAX_CHARS(types.u8byte)); sprintf(str, "%lld", (long long)types.s8byte); ok1(strlen(str) < STR_MAX_CHARS(types.s8byte)); /* Pointer version. */ sprintf(str, "%p", types.ptr); ok1(strlen(str) < STR_MAX_CHARS(types.ptr)); return exit_status(); } horst-4.2/ccan/str/test/run.c000066400000000000000000000051321241274412600161650ustar00rootroot00000000000000#include #include #include #include #include #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) static const char *substrings[] = { "far", "bar", "baz", "b", "ba", "z", "ar", NULL }; #define NUM_SUBSTRINGS (ARRAY_SIZE(substrings) - 1) static char *strdup_rev(const char *s) { char *ret = strdup(s); unsigned int i; for (i = 0; i < strlen(s); i++) ret[i] = s[strlen(s) - i - 1]; return ret; } int main(int argc, char *argv[]) { unsigned int i, j, n; char *strings[NUM_SUBSTRINGS * NUM_SUBSTRINGS]; n = 0; for (i = 0; i < NUM_SUBSTRINGS; i++) { for (j = 0; j < NUM_SUBSTRINGS; j++) { strings[n] = malloc(strlen(substrings[i]) + strlen(substrings[j]) + 1); sprintf(strings[n++], "%s%s", substrings[i], substrings[j]); } } plan_tests(n * n * 5 + 16); for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { unsigned int k, identical = 0; char *reva, *revb; /* Find first difference. */ for (k = 0; strings[i][k]==strings[j][k]; k++) { if (k == strlen(strings[i])) { identical = 1; break; } } if (identical) ok1(streq(strings[i], strings[j])); else ok1(!streq(strings[i], strings[j])); /* Postfix test should be equivalent to prefix * test on reversed string. */ reva = strdup_rev(strings[i]); revb = strdup_rev(strings[j]); if (!strings[i][k]) { ok1(strstarts(strings[j], strings[i])); ok1(strends(revb, reva)); } else { ok1(!strstarts(strings[j], strings[i])); ok1(!strends(revb, reva)); } if (!strings[j][k]) { ok1(strstarts(strings[i], strings[j])); ok1(strends(reva, revb)); } else { ok1(!strstarts(strings[i], strings[j])); ok1(!strends(reva, revb)); } free(reva); free(revb); } } for (i = 0; i < n; i++) free(strings[i]); ok1(streq(stringify(NUM_SUBSTRINGS), "((sizeof(substrings) / sizeof(substrings[0])) - 1)")); ok1(streq(stringify(ARRAY_SIZE(substrings)), "(sizeof(substrings) / sizeof(substrings[0]))")); ok1(streq(stringify(i == 0), "i == 0")); ok1(strcount("aaaaaa", "b") == 0); ok1(strcount("aaaaaa", "a") == 6); ok1(strcount("aaaaaa", "aa") == 3); ok1(strcount("aaaaaa", "aaa") == 2); ok1(strcount("aaaaaa", "aaaa") == 1); ok1(strcount("aaaaaa", "aaaaa") == 1); ok1(strcount("aaaaaa", "aaaaaa") == 1); ok1(strcount("aaa aaa", "b") == 0); ok1(strcount("aaa aaa", "a") == 6); ok1(strcount("aaa aaa", "aa") == 2); ok1(strcount("aaa aaa", "aaa") == 2); ok1(strcount("aaa aaa", "aaaa") == 0); ok1(strcount("aaa aaa", "aaaaa") == 0); return exit_status(); } horst-4.2/channel.c000066400000000000000000000072311241274412600143000ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 "wext.h" #include "channel.h" #if defined(__APPLE__) int channel_change(__attribute__((unused)) int idx) { return 0; } int channel_auto_change(void) { return 0; } int channel_find_index_from_chan(__attribute__((unused)) int c) { return -1; } void get_current_channel(__attribute__((unused)) int mon) { } #else static struct timeval last_channelchange; extern int mon; /* monitoring socket */ static struct chan_freq channels[MAX_CHANNELS]; int channel_change(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.channel_idx = idx; return 1; } int channel_auto_change(void) { 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.channel_idx; 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 = channel_change(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; } int channel_find_index_from_chan(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; } int channel_find_index_from_freq(int f) { int i = -1; for (i = 0; i < conf.num_channels && i < MAX_CHANNELS; i++) if (channels[i].freq == f) return i; return -1; } int channel_get_chan_from_idx(int i) { if (i >= 0 && i < conf.num_channels && i < MAX_CHANNELS) return channels[i].chan; else return -1; } int channel_get_current_chan() { return channel_get_chan_from_idx(conf.channel_idx); } static int get_current_wext_channel_idx(int mon) { int freq, ch; /* get current channel & map to our channel array */ freq = wext_get_freq(mon, conf.ifname); if (freq == 0) return -1; ch = channel_find_index_from_freq(freq); DEBUG("***%d\n", ch); return ch; } void channel_init(void) { /* get available channels */ conf.num_channels = wext_get_channels(mon, conf.ifname, channels); conf.channel_idx = get_current_wext_channel_idx(mon); } struct chan_freq* channel_get_struct(int i) { if (i < conf.num_channels && i < MAX_CHANNELS) return &channels[i]; return NULL; } void channel_set(int i, int chan, int freq) { if (i < conf.num_channels && i < MAX_CHANNELS) { channels[i].chan = chan; channels[i].freq = freq; } } #endif horst-4.2/channel.h000066400000000000000000000025351241274412600143070ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 _CHANNEL_H_ #define _CHANNEL_H_ #define MAX_CHANNELS 64 /* channel to frequency mapping */ struct chan_freq { int chan; int freq; }; int channel_change(int idx); int channel_auto_change(void); int channel_find_index_from_chan(int c); int channel_find_index_from_freq(int f); void get_current_channel(int mon); int channel_get_chan_from_idx(int idx); int channel_get_current_chan(); void channel_init(void); struct chan_freq* channel_get_struct(int idx); void channel_set(int idx, int chan, int freq); #endif horst-4.2/config.h000066400000000000000000000003221241274412600141340ustar00rootroot00000000000000/* Generated by CCAN configurator */ #ifndef CCAN_CONFIG_H #define CCAN_CONFIG_H #ifndef _GNU_SOURCE #define _GNU_SOURCE /* Always use GNU extensions. */ #endif #define HAVE_TYPEOF 1 #endif /* CCAN_CONFIG_H */ horst-4.2/control.c000066400000000000000000000063631241274412600143550ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 "main.h" #include "channel.h" #include "control.h" #define MAX_CMD 255 /* FIFO (named pipe) */ int ctlpipe = -1; void control_init_pipe(void) { mkfifo(conf.control_pipe, 0666); ctlpipe = open(conf.control_pipe, O_RDWR|O_NONBLOCK); } void control_send_command(char* cmd) { int len = strlen(cmd); char new[len+1]; char* pos; while (access(conf.control_pipe, F_OK) < 0) { printf("Waiting for control pipe...\n"); sleep(1); } ctlpipe = open(conf.control_pipe, O_WRONLY); if (ctlpipe < 0) err(1, "Could not open control socket '%s'", conf.control_pipe); /* always terminate command with newline */ strncpy(new, cmd, len); new[len] = '\n'; new[len+1] = '\0'; /* replace : with newline */ while ((pos = strchr(new, ':')) != NULL) { *pos = '\n'; } printf("Sending command: %s\n", new); write(ctlpipe, new, len+1); close(ctlpipe); } static void parse_command(char* in) { char* cmd; char* val; int n; cmd = strsep(&in, "="); val = in; //printlog("RECV CMD %s VAL %s", cmd, val); /* commands without value */ if (strcmp(cmd, "pause") == 0) { main_pause(1); } else if (strcmp(cmd, "resume") == 0) { main_pause(0); } /* all other commands require a value */ if (val == NULL) return; else if (strcmp(cmd, "channel") == 0) { n = atoi(val); printlog("- CHANNEL = %d", n); conf.do_change_channel = 0; channel_change(channel_find_index_from_chan(n)); } else if (strcmp(cmd, "channel_auto") == 0) { n = (strcmp(val, "1") == 0); printlog("- CHANNEL AUTO = %d", n); conf.do_change_channel = n; } else if (strcmp(cmd, "channel_dwell") == 0) { n = atoi(val); printlog("- CHANNEL DWELL = %d", n); conf.channel_time = n*1000; } else if (strcmp(cmd, "channel_upper") == 0) { n = atoi(val); printlog("- CHANNEL MAX = %d", n); conf.channel_max = n; } else if (strcmp(cmd, "outfile") == 0) { dumpfile_open(val); } } void control_receive_command(void) { char buf[MAX_CMD]; char *pos = buf; char *end; int len; len = read(ctlpipe, buf, MAX_CMD); if (len > 0) { buf[len] = '\0'; /* we can receive multiple \n separated commands */ while ((end = strchr(pos, '\n')) != NULL) { *end = '\0'; parse_command(pos); pos = end + 1; } } } void control_finish(void) { if (ctlpipe == -1) return; close(ctlpipe); unlink(conf.control_pipe); ctlpipe = -1; } horst-4.2/control.h000066400000000000000000000020111241274412600143440ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 _CONTROL_H_ #define _CONTROL_H_ extern int ctlpipe; void control_init_pipe(); void control_send_command(char* cmd); void control_receive_command(); void control_finish(void); #endif horst-4.2/display-channel.c000066400000000000000000000046401241274412600157440ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 "channel.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 ", channel_get_current_chan()); print_centered(win, 8, 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 = channel_find_index_from_chan(x); if (x >= 0) { if (!conf.serveraddr) channel_change(x); else conf.channel_idx = x; } break; default: return 0; /* didn't handle input */ } net_send_channel_config(); update_channel_win(win); return 1; } horst-4.2/display-essid.c000066400000000000000000000045451241274412600154470ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 Sig E IP"); list_for_each(&essids.list, e, 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(&e->nodes, n, 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, " %3d", n->last_pkt.phy_signal); 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-4.2/display-filter.c000066400000000000000000000201161241274412600156150ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 "wlan80211.h" #include "network.h" #define CHECKED(_x) (conf.filter_pkt & (_x)) ? '*' : ' ' #define CHECKED_MODE(_x) (conf.filter_mode & (_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 26 void update_filter_win(WINDOW *win) { int l, i; box(win, 0 , 0); print_centered(win, 0, 57, " Edit Filters "); l = 2; wattron(win, get_packet_type_color(WLAN_FRAME_TYPE_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(WLAN_FRAME_TYPE_CTRL)); 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_RTSCTS)); mvwprintw(win, l++, 2, "k: [%c] ACK", CHECKED(PKT_TYPE_ACK)); l++; wattron(win, get_packet_type_color(WLAN_FRAME_TYPE_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, "Q: [%c] QoS Data", CHECKED(PKT_TYPE_QDATA)); 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++; wattron(win, RED); mvwprintw(win, l++, 2, "*: [%c] Bad FCS", CHECKED(PKT_TYPE_BADFCS)); wattroff(win, RED); l = 2; 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++; 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, "Mode"); wattroff(win, A_BOLD); mvwprintw(win, l++, MAC_COL, "A: [%c] Access Point", CHECKED_MODE(WLAN_MODE_AP)); mvwprintw(win, l++, MAC_COL, "S: [%c] Station", CHECKED_MODE(WLAN_MODE_STA)); mvwprintw(win, l++, MAC_COL, "I: [%c] IBSS (Ad-hoc)", CHECKED_MODE(WLAN_MODE_IBSS)); mvwprintw(win, l++, MAC_COL, "O: [%c] Probe Request", CHECKED_MODE(WLAN_MODE_PROBE)); mvwprintw(win, l++, MAC_COL, "W: [%c] WDS/4ADDR", CHECKED_MODE(WLAN_MODE_4ADDR)); mvwprintw(win, l++, MAC_COL, "N: [%c] Unknown", CHECKED_MODE(WLAN_MODE_UNKNOWN)); l++; wattron(win, A_BOLD); mvwprintw(win, l++, MAC_COL, "0: [%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_RTSCTS); 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 'Q': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_QDATA); 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); break; case 'B': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_BATMAN); break; case 'M': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_MESHZ); break; case '*': TOGGLE_BIT(conf.filter_pkt, PKT_TYPE_BADFCS); break; case 'A': TOGGLE_BIT(conf.filter_mode, WLAN_MODE_AP); break; case 'S': TOGGLE_BIT(conf.filter_mode, WLAN_MODE_STA); break; case 'I': TOGGLE_BIT(conf.filter_mode, WLAN_MODE_IBSS); break; case 'O': TOGGLE_BIT(conf.filter_mode, WLAN_MODE_PROBE); break; case 'W': TOGGLE_BIT(conf.filter_mode, WLAN_MODE_4ADDR); break; case 'N': TOGGLE_BIT(conf.filter_mode, WLAN_MODE_UNKNOWN); break; case 's': echo(); print_centered(win, FILTER_MAX, 57, "[ Enter new BSSID and ENTER ]"); mvwprintw(win, 3, MAC_COL + 4, ">"); mvwgetnstr(win, 3, 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, 6 + i, MAC_COL + 4, ">"); mvwgetnstr(win, 6 + 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 '0': conf.filter_off = conf.filter_off ? 0 : 1; break; default: return 0; } /* convenience: */ /* if one of the individual subtype frames is selected we enable the general frame type */ if (conf.filter_pkt & PKT_TYPE_ALL_MGMT) conf.filter_pkt |= PKT_TYPE_MGMT; if (conf.filter_pkt & PKT_TYPE_ALL_CTRL) conf.filter_pkt |= PKT_TYPE_CTRL; if (conf.filter_pkt & PKT_TYPE_ALL_DATA) 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-4.2/display-help.c000066400000000000000000000044101241274412600152570ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 "wlan_util.h" void update_help_win(WINDOW *win) { int i, l; struct pkt_name 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 (or)"); print_centered(win, 3, COLS, "HORST - Highly Optimized Radio Scanning Tool"); print_centered(win, 5, COLS, "Version " VERSION " (build date " __DATE__ " " __TIME__ ")"); print_centered(win, 6, COLS, "(C) 2005-2014 Bruno Randolf, Licensed under the GPLv2"); mvwprintw(win, 8, 2, "Known IEEE802.11 Packet Types:"); l = 10; /* this is weird but it works */ mvwprintw(win, l++, 2, "MANAGEMENT FRAMES"); for (i = 0x00; i <= 0xE0; i = i + 0x10) { c = get_packet_struct(i); if (c.c != '?') mvwprintw(win, l++, 4, "%c %-6s %s", c.c, c.name, c.desc); } l = 10; mvwprintw(win, l++, 45, "DATA FRAMES"); for (i = 0x08; i <= 0xF8; i = i + 0x10) { c = get_packet_struct(i); if (c.c != '?') mvwprintw(win, l++, 47, "%c %-6s %s", c.c, c.name, c.desc); } mvwprintw(win, l++, 2, "CONTROL FRAMES"); for (i = 0x74; i <= 0xF4; i = i + 0x10) { c = get_packet_struct(i); if (c.c != '?') mvwprintw(win, l++, 4, "%c %-6s %s", c.c, c.name, c.desc); } print_centered(win, ++l, COLS, "For more info read the man page or check http://br1.einfach.org/horst/"); wrefresh(win); } horst-4.2/display-history.c000066400000000000000000000063741241274412600160430ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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" #include "wlan_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, rat; if (col > MAX_HISTORY) col = 4 + MAX_HISTORY; werase(win); wattron(win, WHITE); box(win, 0 , 0); print_centered(win, 0, COLS, " Signal/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, CYAN); mvwprintw(win, TYPE_POS, 1, "TYP"); mvwprintw(win, 2, col-11, "Packet Type"); wattron(win, A_BOLD); wattron(win, BLUE); mvwprintw(win, 3, col-4, "Rate"); mvwprintw(win, RATE_POS-12, 1, "300"); mvwprintw(win, RATE_POS-11, 1, "275"); mvwprintw(win, RATE_POS-10, 1, "250"); mvwprintw(win, RATE_POS-9, 1, "225"); mvwprintw(win, RATE_POS-8, 1, "200"); mvwprintw(win, RATE_POS-7, 1, "175"); mvwprintw(win, RATE_POS-6, 1, "150"); mvwprintw(win, RATE_POS-5, 1, "125"); mvwprintw(win, RATE_POS-4, 1, "100"); mvwprintw(win, RATE_POS-3, 1, " 75"); mvwprintw(win, RATE_POS-2, 1, " 50"); mvwprintw(win, RATE_POS-1, 1, " 25"); wattroff(win, A_BOLD); i = hist.index - 1; while (col > 4 && hist.signal[i] != 0) { sig = normalize_db(-hist.signal[i], SIGN_POS - 1); wattron(win, ALLGREEN); mvwvline(win, sig + 1, col, ACS_BLOCK, SIGN_POS - sig - 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"); rat = hist.rate[i]/250; 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-4.2/display-main.c000066400000000000000000000353611241274412600152640ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 "wlan80211.h" #include "wlan_util.h" #include "olsr_header.h" #include "batman_adv_header-14.h" #include "listsort.h" #include "channel.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_node*, const struct list_node*) = 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_signal(const struct list_node *p1, const struct list_node *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_signal > n2->last_pkt.phy_signal) return -1; else if (n1->last_pkt.phy_signal == n2->last_pkt.phy_signal) return 0; else return 1; } static int compare_nodes_time(const struct list_node *p1, const struct list_node *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_node *p1, const struct list_node *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_node *p1, const struct list_node *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_signal; 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; /* no break */ case '\r': case KEY_ENTER: delwin(sort_win); sort_win = NULL; update_display(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:Signal 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, 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->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); mvwprintw(stat_win, 0, 1, "Sig: %5d", p->phy_signal); signal_average_bar(stat_win, sig, siga, STAT_START, 2, stat_height, 2); } 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, 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, 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_SIG COL_CHAN + 3 #define COL_RATE COL_SIG + 4 #define COL_SOURCE COL_RATE + 4 #define COL_MODE COL_SOURCE + 18 #define COL_ENC COL_MODE + 9 #define COL_ESSID COL_ENC + 6 #define COL_INFO COL_ESSID + 13 static char spin[4] = {'/', '-', '\\', '|'}; static void print_node_list_line(int line, struct node_info* n) { struct packet_info* p = &n->last_pkt; char* ssid = NULL; 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); if (n->wlan_channel) mvwprintw(list_win, line, COL_CHAN, "%2d", n->wlan_channel ); mvwprintw(list_win, line, COL_SIG, "%3d", -ewma_read(&n->phy_sig_avg)); mvwprintw(list_win, line, COL_RATE, "%3d", p->phy_rate/10); mvwprintw(list_win, line, COL_SOURCE, "%s", ether_sprintf(p->wlan_src)); if (n->wlan_mode & WLAN_MODE_AP) { wprintw(list_win, " AP"); if (n->essid != NULL) ssid = n->essid->essid; } if (n->wlan_mode & WLAN_MODE_IBSS) { wprintw(list_win, " ADH"); if (n->essid != NULL) ssid = n->essid->essid; } if (n->wlan_mode & WLAN_MODE_STA) { wprintw(list_win, " STA"); if (n->wlan_ap_node != NULL && n->wlan_ap_node->essid != NULL) ssid = n->wlan_ap_node->essid->essid; } if (n->wlan_mode & WLAN_MODE_PROBE) { wprintw(list_win, " PRB"); ssid = p->wlan_essid; } if (n->wlan_mode & WLAN_MODE_4ADDR) { wprintw(list_win, " WDS"); } if (n->wlan_rsn && n->wlan_wpa) mvwprintw(list_win, line, COL_ENC, "WPA12"); else if (n->wlan_rsn) mvwprintw(list_win, line, COL_ENC, "WPA2"); else if (n->wlan_wpa) mvwprintw(list_win, line, COL_ENC, "WPA1"); else if (n->wlan_wep) mvwprintw(list_win, line, COL_ENC, "WEP?"); if (ssid != NULL) mvwprintw(list_win, line, COL_ESSID, "%s ", ssid); if (ssid == NULL || strlen(ssid) < 12) wmove(list_win, line, COL_INFO); if (n->pkt_types & PKT_TYPE_OLSR) wprintw(list_win, "OLSR N:%d ", n->olsr_neigh); if (n->pkt_types & PKT_TYPE_BATMAN) wprintw(list_win, "BATMAN %s", n->bat_gw ? "GW " : ""); if (n->pkt_types & (PKT_TYPE_MESHZ)) wprintw(list_win, "MC "); if (n->pkt_types & PKT_TYPE_IP) wprintw(list_win, "%s", ip_sprintf(n->ip_src)); wattroff(list_win, A_BOLD); wattroff(list_win, GREEN); wattroff(list_win, RED); } static void update_node_list_win(void) { struct node_info* n; int line = 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_SIG, "Sig"); mvwprintw(list_win, 0, COL_RATE, "RAT"); mvwprintw(list_win, 0, COL_SOURCE, "TRANSMITTER"); mvwprintw(list_win, 0, COL_MODE, "MODE"); mvwprintw(list_win, 0, COL_ENC, "ENCR"); mvwprintw(list_win, 0, COL_ESSID, "ESSID"); mvwprintw(list_win, 0, COL_INFO, "INFO"); /* reuse bottom line for information on other win */ mvwprintw(list_win, win_split - 1, 0, "CH-Sig"); wprintw(list_win, "-RAT-TRANSMITTER"); mvwprintw(list_win, win_split - 1, 29, "(BSSID)"); mvwprintw(list_win, win_split - 1, 49, "TYPE"); mvwprintw(list_win, win_split - 1, 56, "INFO"); mvwprintw(list_win, win_split - 1, COLS-10, "LiveStatus"); if (sortfunc) listsort(&nodes.n, sortfunc); list_for_each(&nodes, n, list) { if (conf.filter_mode != 0 && (n->wlan_mode & conf.filter_mode) == 0) continue; line++; if (line >= win_split - 1) break; /* prevent overdraw of last line */ print_node_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); if (p->phy_flags & PHY_FLAG_BADFCS) wattron(dump_win, RED); wprintw(dump_win, "\n%02d ", p->wlan_channel); wprintw(dump_win, "%03d ", p->phy_signal); wprintw(dump_win, "%3d ", p->phy_rate/10); wprintw(dump_win, "%s ", ether_sprintf(p->wlan_src)); wprintw(dump_win, "(%s) ", ether_sprintf(p->wlan_bssid)); if (p->phy_flags & PHY_FLAG_BADFCS) { wprintw(dump_win, "*BADFCS* "); return; } if ((p->pkt_types & PKT_TYPE_BATMAN) && p->bat_packet_type == BAT_UNICAST) { /* unicast traffic can carry IP/ICMP which we show below */ wprintw(dump_win, "BATMAN "); } 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) && p->bat_packet_type != BAT_UNICAST) { wprintw(dump_win, "BATMAN "); switch (p->bat_packet_type) { case BAT_OGM: wprintw(dump_win, "OGM"); break; case BAT_ICMP: wprintw(dump_win, "BAT_ICMP"); break; case BAT_BCAST: wprintw(dump_win, "BCAST"); break; case BAT_VIS: wprintw(dump_win, "VIS"); break; case BAT_UNICAST_FRAG: wprintw(dump_win, "FRAG"); break; case BAT_TT_QUERY: wprintw(dump_win, "TT_QUERY"); break; case BAT_ROAM_ADV: wprintw(dump_win, "ROAM_ADV"); break; default: wprintw(dump_win, "UNKNOWN %d", p->bat_packet_type); } } 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) { case WLAN_FRAME_DATA: case WLAN_FRAME_DATA_CF_ACK: case WLAN_FRAME_DATA_CF_POLL: case WLAN_FRAME_DATA_CF_ACKPOLL: case WLAN_FRAME_QDATA: case WLAN_FRAME_QDATA_CF_ACK: case WLAN_FRAME_QDATA_CF_POLL: case WLAN_FRAME_QDATA_CF_ACKPOLL: if ( p->wlan_wep == 1) wprintw(dump_win, "ENCRYPTED"); break; case WLAN_FRAME_CTS: case WLAN_FRAME_RTS: case WLAN_FRAME_ACK: case WLAN_FRAME_BLKACK: case WLAN_FRAME_BLKACK_REQ: wprintw(dump_win, "%s", ether_sprintf(p->wlan_dst)); break; case WLAN_FRAME_BEACON: case WLAN_FRAME_PROBE_RESP: wprintw(dump_win, "'%s' %llx", p->wlan_essid, p->wlan_tsf); break; case WLAN_FRAME_PROBE_REQ: wprintw(dump_win, "'%s'", p->wlan_essid); break; } } if (p->wlan_retry) wprintw(dump_win, " [r]"); wattroff(dump_win, A_BOLD); } void update_main_win(struct packet_info *p) { update_node_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(int 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); } void clear_display_main(void) { werase(dump_win); werase(stat_win); } horst-4.2/display-spectrum.c000066400000000000000000000105551241274412600162000ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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, 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", channel_get_chan_from_idx(i)); 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); } /* 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(&spectrum[i].nodes, cn, 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, 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-4.2/display-statistics.c000066400000000000000000000122601241274412600165230ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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" #include "wlan_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); if (i <= 12) mvwprintw(win, line, 2, "%3dM", rate_index_to_rate(i)/10); else mvwprintw(win, line, 2, "MCS%d", i - 12); 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-4.2/display.c000066400000000000000000000307121241274412600143350ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 "wlan80211.h" #include "channel.h" static WINDOW *conf_win = NULL; static WINDOW *show_win = NULL; static int conf_win_current; static int show_win_current; static struct timeval last_time; static int display_resize_needed = 0; /* main windows are special */ void init_display_main(void); void clear_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); static void resize_display_all(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 long bytes, unsigned long duration, unsigned long packets, unsigned long 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) { if (type == 1) /* special case for bad FCS */ return RED; switch (type & WLAN_FRAME_FC_TYPE_MASK) { case WLAN_FRAME_TYPE_DATA: return BLUE; case WLAN_FRAME_TYPE_CTRL: return WHITE; case WLAN_FRAME_TYPE_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 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 != PKT_TYPE_ALL || conf.filter_mode != WLAN_MODE_ALL)) mvwprintw(stdscr, LINES-1, COLS-22, "|F"); else mvwprintw(stdscr, LINES-1, COLS-22, "| "); mvwprintw(stdscr, LINES-1, COLS-20, "|Ch%02d", channel_get_current_chan()); 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(27, 57, LINES/2-13, COLS/2-28); update_filter_win(conf_win); } else if (key == 'c') { conf_win = newwin(9, 39, LINES/2-6, 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) { /* * 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; } if (display_resize_needed == 1) { resize_display_all(); display_resize_needed = 0; } 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 *******************/ static void resize_display_all(void) { struct winsize winsz; /* get new window size */ 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_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); } } static void window_change_handler(__attribute__((unused)) int sig) { display_resize_needed = 1; } /******************* 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': main_pause(conf.paused = conf.paused ? 0 : 1); break; case 'q': case 'Q': exit(0); case 'r': case 'R': clear_display_main(); 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_spectrum(); 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); } /******************* 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); signal(SIGWINCH, window_change_handler); conf.display_initialized = 1; } void finish_display(void) { endwin(); } horst-4.2/display.h000066400000000000000000000041141241274412600143370ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 long bytes, unsigned long duration, unsigned long packets, unsigned long 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 width, short color, short color_avg); void update_display(struct packet_info* pkg); 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-4.2/essid.c000066400000000000000000000072351241274412600140030ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 "wlan80211.h" #include "essid.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(&e->nodes, n, 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; if (n == NULL || (p->phy_flags & PHY_FLAG_BADFCS)) return; /* ignore */ /* only check beacons and probe response frames */ if ((p->wlan_type != WLAN_FRAME_BEACON) && (p->wlan_type != WLAN_FRAME_PROBE_RESP)) 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(&essids.list, e, list) { if (strncmp(e->essid, p->wlan_essid, WLAN_MAX_SSID_LEN) == 0) { DEBUG("SPLIT essid found\n"); break; } } /* if not add new essid */ if (&e->list == &essids.list.n) { DEBUG("SPLIT essid not found, adding new\n"); e = malloc(sizeof(struct essid_info)); strncpy(e->essid, p->wlan_essid, WLAN_MAX_SSID_LEN); e->essid[WLAN_MAX_SSID_LEN-1] = '\0'; e->num_nodes = 0; e->split = 0; list_head_init(&e->nodes); list_add_tail(&essids.list, &e->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(&e->nodes, &n->essid_nodes); e->num_nodes++; n->essid = e; } update_essid_split_status(e); } horst-4.2/essid.h000066400000000000000000000017441241274412600140070ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 _ESSID_H_ #define _ESSID_H_ void remove_node_from_essid(struct node_info* n); void update_essids(struct packet_info* p, struct node_info* n); #endif horst-4.2/horst.1000066400000000000000000000345541241274412600137550ustar00rootroot00000000000000.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH HORST 8 "September 23, 2014" .\" Please adjust this date whenever revising the manpage. .SH NAME horst \- Highly Optimized Radio Scanning Tool .SH SYNOPSIS .B horst .RB [\| \-h \|] .RB [\| \-q \|] .RB [\| \-D \|] .RB [\| \-i .IR interface \|] .RB [\| \-t .IR sec \|] .RB [\| \-d .IR ms \|] .RB [\| \-b .IR bytes \|] .RB [\| \-s \|] .RB [\| \-u \|] .RB [\| \-C \|] .RB [\| \-c .IR IP \|] .RB [\| \-p .IR port \|] .RB [\| \-o .IR file \|] .RB [\| \-X .IR name \|] .RB [\| \-x .IR command \|] .RB [\| \-e .IR mac \|] .RB [\| \-f .IR pkt_name \|] .RB [\| \-m .IR mode \|] .SH DESCRIPTION \fBhorst\fP is a small, lightweight IEEE802.11 wireless LAN analyzer with a text interface. Its basic function is similar to tcpdump, Wireshark or Kismet, but it's much smaller and shows different, aggregated information which is not easily available from other tools. It is mainly targeted at debugging wireless LANs with a focus on ad\-hoc (IBSS) mode in larger mesh networks. It can be useful to get a quick overview of what's going on on all wireless LAN channels and to identify problems. .IP \[bu] 2 Shows signal values per station. .IP \[bu] 2 Calculates channel utilization ("usage") by adding up the amount of time the packets actually occupy the medium. .IP \[bu] 2 "Spectrum Analyzer" shows signal levels and usage per channel. .IP \[bu] 2 Text-based "graphical" packet history, with signal, packet type and physical rate .IP \[bu] 2 Shows all stations per ESSID and the live TSF per node as it is counting. .IP \[bu] 2 Detects IBSS "splits" (same ESSID but different BSSID \- this is a common driver problem). .IP \[bu] 2 Statistics of packets/bytes per physical rate and per packet type. .IP \[bu] 2 Has some support for mesh protocols (OLSR and batman). .IP \[bu] 2 Can filter specific packet types, source MAC addresses or BSSIDs. .IP \[bu] 2 Client/server support for monitoring on remote nodes. .IP \[bu] 2 Can be controlled via a named pipe. .SH OPTIONS .TP .BI \-h Show summary of options. .TP .BI \-q Quiet mode. Don't show user interface. This is only useful in conjunction when running in server mode (\-C) or writing to a file (\-o). .TP .BI \-D Show lot's of debugging output, including a full package dump. Only available when compiled with DEBUG=1. .TP .BI \-i\ intf Operate on given network interface instead of the default "wlan0". Note that the interface is assumed to be in monitor mode already. See MONITOR MODE below for more information about preparing the network interface. .TP .BI \-t\ sec Timeout (remove) nodes after not receiving packets from them for this time in seconds (default: 60 sec). .TP .BI \-d\ ms Display update interval. The default value of 100ms can be increased to reduce CPU load caused by redrawing the screen. .TP .BI \-b\ bytes Receive buffer size. The receive buffer size can be set to tune memory consumption and reduce lost packets under load. .TP .BI \-s Show a poor mans "spectrum analyzer". The same can be achieved by running \fBhorst\fP as normal and pressing the button 's' (Spec); then 'c' (Chan) and 'a' (Automatically change channel). .TP .BI \-u Upper channel limit for the automatic channel change. .TP .BI \-C Allow client connections. Server mode. Only one client connection is supported at the moment (default: off). .TP .BI \-c\ IP Connect to a \fBhorst\fP instance running in server-mode at the specified IP address. .TP .BI \-p\ port Use the specified port (default: 4444) for client/server connections. .TP .BI \-o\ filename Write a information about each received packet into file. Note that you can send to STDOUT by using \fB-o /dev/stdout\fP. See OUTPUT FILE FORMAT below. .TP .BI \-X Accept control commands on a named pipe (default /tmp/horst). .TP .BI "\-X"name Accept control commands on a named pipe with given name or set pipe name used with -x. .TP .BI \-x\ command Send control command to another \fBhorst\fP process who was started with -X and then exit. Multiple commands can be concatenated with ':'. Currently implemented commands are: pause Pause \fBhorst\fP processing resume Resume \fBhorst\fP processing channel=X Set channel channel number channel_auto=X Automatically change channels (1 or 0) channel_dwell=X Set channel dwell time when automatically changing channel (ms) channel_upper=X Set max channel when automatically changing channel outfile=X Write to outfile named X. If the file is already open, it is cleared and re-openend. If filename is not specified ("outfile=") any existing file is closed and no file is written. .TP .BI \-e\ MAC Filter all MAC addresses except these, to show only packets originating from the specified MAC addresses. This option can be specified multiple times. .TP .BI \-f\ pkt_type Filter all packets except these. This option can be specified multiple times. For valid packet names see NAMES AND ABBREVIATIONS below. .TP .BI \-m\ (AP|STA|ADH|PRB|WDS|UNKNOWN) Only show/include packets and nodes of this mode. Note that the mode is infered by the information of packets we received and it may take some time until a node is properly classified. This option can be specified multiple times. .SH TEXT USER INTERFACE The ncurses-based text interface tries to display a lot of information, so it may look confusing at first. Below we describe the different screens and options. .TP Main screen The initial (main) screen is split into three parts. The upper area shows a list of aggregated "node" information, the most useful information about each sender which was discovered, one per line: / "Spinner" to show activity Pk Count of packets Re% Percentage of Re-sent frames CH Channel Sig Signal value (RSSI) in dBm RAT Physical data rate TRANSMITTER MAC address of sender MODE Operating Mode (AP, AHD, PRB, STA, WDS), see "NAMES AND ABBREVIATIONS" ENCR Encryption (WPA1, WPA2, WEP) ESSID ESSID INFO Additional info like "BATMAN", IP address... The lower area shows a scrolling list of packets as they come in: CH Channel Sig Signal value (RSSI) in dBm RAT Physical data rate TRANSMITTER MAC address of sender BSSID BSSID TYPE Packet type, see "NAMES AND ABBREVIATIONS" INFO Additional info like ESSID, TFS, IP address... The lower right box shows bar graphs for: Signal of last received packet in green bps Bits per second of all received packets Usage Percentage of channel use The lower edge is the menu and status bar, it shows which keys to press for other screens. The status shows ">" when \fBhorst\fP is running or "=" when it is paused, then "F" when any kind of filter is active, the Channel, the monitor interface in use and the time. .TP Pause ('p' or ) Can be used to pause/resume \fBhorst\fP. When \fBhorst\fP is paused it will loose packets received in the mean time. .TP Reset ('r') Clears all history and aggregated statistical data. .TP History ('h') The history screen scrolls from right to left and shows a bar for each packet indicating the signal level. In the line below that, the packet type is indicated by one character (See NAMES AND ABBREVIATIONS below) and the rough physical data rate is indicated below that in blue. .TP ESSID ('e') The ESSID screen groups information by ESSID and shows the mode (AP, IBSS), the MAC address of the sender, the BSSID, the TSF, the beacon interval, the channel, the signal, a "W" when encrytoion is used and the IP address if known. .TP Statistics ('a') The statistics screen groups packets by physical rate and by packet type and shows other kinds of aggregated and statistical information based on packets. .TP Spectrum Analyzer ('s') The "poor mans spectrum analyzer" screen is only really useful when \fBhorst\fP is started with the -s option or the "Automatically change channel" option is selected in the "Chan" settings. It shows the available channels horizontally and vertical bars for each channel: Signal in green Physical rate in blue Channel usage in orange/brown By pressing the 'n' key, the display can be changed to show only the average signal level on each channel and the last 4 digits of the MAC address of the individual nodes at the level (height) they were received. This can give a quick graphical overview of the distance of nodes. .TP Filters ('f') This configuration dialog can be used to define the active filters. .TP Channel Settings ('c') This configuration dialog can be used to change the channel changing behaviour of \fBhorst\fP or to change to a different channel manually. .TP Sort ('o') Only active in the main screen, can be used to sort the node list in the upper area by Signal, Time, BSSID or Channel. .SH NAMES AND ABBREVIATIONS .TP 802.11 standard frames Management frames: a ASOCRQ Association request A ASOCRP Associaion response a REASRQ Reassociation request A REASRP Reassociation response p PROBRQ Probe request P PROBRP Probe response T TIMING Timing Advertisement B BEACON Beacon t ATIM ATIM D DISASC Disassociation u AUTH Authentication U DEAUTH Deauthentication C ACTION Action c ACTNOA Action No Ack Control frames: w CTWRAP Control Wrapper b BACKRQ Block Ack Request B BACK Block Ack s PSPOLL PS-Poll R RTS RTS C CTS CTS K ACK ACK f CFEND CF-End f CFENDK CF-End + CF-Ack Data frames: D DATA Data F DCFACK Data + CF-Ack F DCFPLL Data + CF-Poll F DCFKPL Data + CF-Ack + CF-Poll n NULL Null (no data) f CFACK CF-Ack (no data) f CFPOLL CF-Poll (no data) f CFCKPL CF-Ack + CF-Poll (no data) Q QDATA QoS Data F QDCFCK QoS Data + CF-Ack F QDCFPL QoS Data + CF-Poll F QDCFKP QoS Data + CF-Ack + CF-Poll N QDNULL QoS Null (no data) f QCFPLL QoS CF-Poll (no data) f QCFKPL QoS CF-Ack + CF-Poll (no data) * BADFCS Bad frame checksum .TP Packet types Similar to 802.11 frames above but higher level and as a bit field (types can overlap, e.g. DATA + IP) and including more information, like IP, ARP, BATMAN, OLSR... CTRL 0x000001 WLAN Control frame MGMT 0x000002 WLAN Management frame DATA 0x000004 WLAN Data frame BADFCS 0x000008 WLAN frame checksum (FCS) bad BEACON 0x000010 WLAN beacon frame PROBE 0x000020 WLAN probe request or response ASSOC 0x000040 WLAN associaction request/response frame AUTH 0x000080 WLAN authentication frame RTSCTS 0x000100 WLAN RTS or CTS ACK 0x000200 WLAN ACK or BlockACK NULL 0x000400 WLAN NULL Data frame QDATA 0x000800 WLAN QoS Data frame (WME/WMM) ARP 0x001000 ARP packet IP 0x002000 IP packet ICMP 0x004000 IP ICMP packet UDP 0x008000 IP UDP TCP 0x010000 IP TCP OLSR 0x020000 OLSR protocol BATMAN 0x040000 BATMAND Layer3 or BATMAN-ADV Layer 2 frame MESHZ 0x080000 MeshCruzer protocol .TP Operating modes Bit field of operating mode type which is infered from received packets. Modes may overlap, i.e. it is common to see STA and PRB at the same time. AP 0x01 Access Point (AP) ADH 0x02 Ad-hoc node STA 0x04 Station (AP client) PRB 0x08 Sent PROBE requests WDS 0x10 WDS or 4 Address frames UNKNOWN 0x20 Unknown e.g. RTS/CTS or ACK .SH MONITOR MODE \fBhorst\fP should work with any wireleass LAN card and driver which supports monitor mode, with either "prism2" or "radiotap" headers. This includes most modern mac80211-based drivers. You have to put your card in monitor mode and set the channel manually before you start \fBhorst\fP. Usually this has to be done as root. Note that depending on the wireless driver capabilities and versions, signal values and ranges may be different. Also, if the monitor interface is added to an existing interface, the driver does not allow the channel to be changed. .TP Using iw: .nf iw wlan0 interface add mon0 type monitor or sudo iw wlan1 set type monitor sudo iw wlan1 set channel 6 .fi .TP Using iwconfig: .nf iwconfig wlan0 mode monitor iwconfig wlan0 channel 1 ifconfig wlan0 up .fi .TP Using madwifi: wlanconfig wlan0 create wlandev wifi0 wlanmode monitor .TP Using hostap: .nf iwconfig wlan0 mode monitor iwpriv wlan0 monitor_type 1 .fi .SH OUTPUT FILE FORMAT The format of the output file (-o flag) is a comma separated list of the following fields in the following order, one packet each line. .TP packet_type 802.11 MAC packet type name as defined in the section "NAMES AND ABBREVIATIONS". .TP wlan_src Source MAC address .TP wlan_dst Destination MAC address .TP wlan_bssid BSSID .TP pkt_types Higher level packet name as defined in section "NAMES AND ABBREVIATIONS". .TP phy_signal Signal strength in dBm .TP phy_noise Noise in dBm (always 0) .TP phy_snr Signal to Noise ratio in dB (always 0, redundant) .TP wlan_len Packet length (MAC) .TP phy_rate Physical data rate .TP phy_freq Received while tuned to this frequency. .TP wlan_tsf TFS timer value .TP wlan_essid ESSID, network name .TP wlan_mode Operating modes as defined in "NAMES AND ABBREVIATIONS". .TP wlan_channel Channel number .TP wlan_wep Encryption in use .TP wlan_wpa WPA1 Encryption in use .TP wlan_rsn RSN (WPA2) Encryption in use .TP ip_src IP source address (if available) .TP ip_dst IP destionation address (if available) .TP olsr_type OLSR message type (if applicable) .TP olsr_neigh OLSR number of neighbours (if applicable) .SH SEE ALSO .BR tcpdump (1), .BR wireshark (1), .BR kismet (1), .BR README, .BI http://br1.einfach.org/tech/horst .SH AUTHOR \fBhorst\fP was written by Bruno Randolf . .PP This manual page was written by Antoine Beaupré , for the Debian project (and may be used by others). horst-4.2/horst.sh000077500000000000000000000014221241274412600142160ustar00rootroot00000000000000#!/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 if [ -n "$1" ]; then # find the phy for device $1 PHY=`iw dev | awk "/phy#[0-9]+/ {phy=\\$1} /Interface/ {if (\\$2 == \"$1\") {sub(\"\#\", \"\", phy); print phy; exit}}"` if [ -n "$PHY" ]; then shift WLDEV=${PHY}mon0 iw phy $PHY interface add $WLDEV type monitor flags fcsfail otherbss ip link set dev $WLDEV up ./horst -i $WLDEV $* ip link set dev $WLDEV down iw dev $WLDEV del else horst $* fi else horst $* fi fi horst-4.2/ieee80211_util.c000066400000000000000000000114341241274412600152300ustar00rootroot00000000000000/* 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 * Copyright 2014 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 version 2 as * published by the Free Software Foundation. * * utilities for mac80211 */ #include #include #include #include "ieee80211_util.h" #include "wlan80211.h" #include "main.h" #include "util.h" /* 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; } static 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; } static const unsigned char ieee802_1d_to_ac[8] = { 0, 1, 1, 0, 2, 2, 3, 3 }; /* BE BK VI VO */ static const unsigned char ac_to_aifs[4] = { 3, 7, 2, 2}; static const unsigned char ac_to_cwmin[4] = { 4, 4, 3, 2}; static 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 (type == WLAN_FRAME_CTS || type == WLAN_FRAME_ACK) { //TODO: also fragments DEBUG("DUR SIFS\n"); dur += sifs; } else if (type == WLAN_FRAME_BEACON) { /* TODO: which AIFS and CW should be used for beacons? */ dur += sifs + (2 * slottime); /* AIFS */ dur += (slottime * 1) / 2; /* contention */ } else if (WLAN_FRAME_IS_DATA(type) && last_was_cts) { DEBUG("DUR LAST CTS\n"); dur += sifs; } else if (type == WLAN_FRAME_QDATA) { 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 (type == WLAN_FRAME_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; } horst-4.2/ieee80211_util.h000066400000000000000000000013611241274412600152330ustar00rootroot00000000000000/* 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 * Copyright 2014 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 version 2 as * published by the Free Software Foundation. * * utilities for mac80211 */ #ifndef _IEEE80211_UTIL_H_ #define _IEEE80211_UTIL_H_ int ieee80211_frame_duration(int phymode, size_t len, int rate, int short_preamble, int ackcts, int shortslot, char qos_class, int retries); #endif horst-4.2/licenses/000077500000000000000000000000001241274412600143265ustar00rootroot00000000000000horst-4.2/licenses/BSD-MIT000066400000000000000000000017771241274412600153240ustar00rootroot00000000000000Permission 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 THE AUTHORS OR COPYRIGHT HOLDERS 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. horst-4.2/licenses/CC0000066400000000000000000000143571241274412600146300ustar00rootroot00000000000000Statement of Purpose The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; moral rights retained by the original author(s) and/or performer(s); publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; rights protecting the extraction, dissemination, use and reuse of data in a Work; database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 4. Limitations and Disclaimers. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. horst-4.2/listsort.c000066400000000000000000000161671241274412600145630ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 "ccan/list/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_node *head, int(*cmp)(const struct list_node*, const struct list_node*)) { struct list_node *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; list_head_init(&lh); e[0].i = 5; e[1].i = 2; e[2].i = 1; e[3].i = 3; e[4].i = 4; list_add_tail(&lh, &e[0].list); list_add_tail(&lh, &e[1].list); list_add_tail(&lh, &e[2].list); list_add_tail(&lh, &e[3].list); list_add_tail(&lh, &e[4].list); list_for_each(&lh, ep, list) { printf("%d ", ep->i); } printf("\n"); listsort(&lh, &elem_cmp); list_for_each(&lh, ep, 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-4.2/listsort.h000066400000000000000000000017561241274412600145660ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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_node *list, int(*cmp)(const struct list_node*, const struct list_node*)); #endif horst-4.2/main.c000066400000000000000000000531771241274412600136260ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 "main.h" #include "util.h" #include "capture.h" #include "protocol_parser.h" #include "network.h" #include "display.h" #include "wlan_util.h" #include "ieee80211_util.h" #include "control.h" #include "channel.h" #include "node.h" #include "essid.h" struct list_head nodes; struct essid_meta_info essids; struct history hist; struct statistics stats; 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, .recv_buffer_size = RECV_BUFFER_SIZE, .port = DEFAULT_PORT, .control_pipe = DEFAULT_CONTROL_PIPE, .filter_pkt = PKT_TYPE_ALL, .filter_mode = WLAN_MODE_ALL, }; 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; 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 || conf.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.rate[hist.index] = p->phy_rate; hist.type[hist.index] = (p->phy_flags & PHY_FLAG_BADFCS) ? 1 : 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) { int type = (p->phy_flags & PHY_FLAG_BADFCS) ? 1 : p->wlan_type; if (p->phy_rate_idx == 0) return; stats.packets++; stats.bytes += p->wlan_len; if (p->wlan_retry) stats.retries++; if (p->phy_rate_idx > 0 && p->phy_rate_idx < MAX_RATES) { stats.duration += p->pkt_duration; stats.packets_per_rate[p->phy_rate_idx]++; stats.bytes_per_rate[p->phy_rate_idx] += p->wlan_len; stats.duration_per_rate[p->phy_rate_idx] += p->pkt_duration; } if (type >= 0 && type < MAX_FSTYPE) { stats.packets_per_type[type]++; stats.bytes_per_type[type] += p->wlan_len; if (p->phy_rate_idx > 0 && p->phy_rate_idx < MAX_RATES) stats.duration_per_type[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->packets++; chan->bytes += p->wlan_len; chan->durations += p->pkt_duration; ewma_add(&chan->signal_avg, -chan->signal); if (!n) { DEBUG("spec no node\n"); return; } /* add node to channel if not already there */ list_for_each(&chan->nodes, cn, 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(&chan->nodes, &cn->chan_list); list_add_tail(&n->on_channels, &cn->node_list); 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.channel_idx >= 0) { spectrum[conf.channel_idx].durations_last = spectrum[conf.channel_idx].durations; spectrum[conf.channel_idx].durations = 0; ewma_add(&spectrum[conf.channel_idx].durations_avg, spectrum[conf.channel_idx].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, %d, ", p->pkt_types, p->phy_signal, 0, 0, p->wlan_len, p->phy_rate, p->phy_freq); fprintf(DF, "%016llx, ", (unsigned long long)p->wlan_tsf); fprintf(DF, "%s, %d, %d, %d, %d, %d, ", p->wlan_essid, p->wlan_mode, p->wlan_channel, p->wlan_wep, p->wlan_wpa, p->wlan_rsn); fprintf(DF, "%s, ", ip_sprintf(p->ip_src)); fprintf(DF, "%s, ", ip_sprintf(p->ip_dst)); fprintf(DF, "%d, %d\n", p->olsr_type, p->olsr_neigh); fflush(DF); } /* return 1 if packet is filtered */ static int filter_packet(struct packet_info* p) { int i; if (conf.filter_off) return 0; if (conf.filter_pkt != PKT_TYPE_ALL && (p->pkt_types & ~conf.filter_pkt)) { stats.filtered_packets++; return 1; } /* cannot trust anything if FCS is bad */ if (p->phy_flags & PHY_FLAG_BADFCS) return 0; if (conf.filter_mode != WLAN_MODE_ALL && ((p->wlan_mode & ~conf.filter_mode) || p->wlan_mode == 0)) { /* this also filters out packets where we cannot associate a mode (ACK, RTS/CTS) */ 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 = NULL; int i = -1; /* filter on server side only */ if (!conf.serveraddr && filter_packet(p)) { if (!conf.quiet && !conf.paused && !conf.debug) update_display_clock(); return; } if (cli_fd != -1) net_send_packet(p); if (conf.dumpfile != NULL && !conf.paused && DF != NULL) write_to_file(p); if (conf.paused) return; DEBUG("handle %s\n", get_packet_type_name(p->wlan_type)); /* get channel index for packet */ if (p->phy_freq) { i = channel_find_index_from_freq(p->phy_freq); } /* not found from pkt, best guess from config but it might be * unknown (-1) too */ if (i < 0) p->pkt_chan_idx = conf.channel_idx; else p->pkt_chan_idx = i; /* wlan_channel is only known for beacons and probe response, * otherwise we set it from the physical channel */ if (p->wlan_channel == 0 && p->pkt_chan_idx >= 0) p->wlan_channel = channel_get_chan_from_idx(p->pkt_chan_idx); /* if current channel is unknown (this is a mac80211 bug), guess it from * the packet */ if (conf.channel_idx < 0 && p->pkt_chan_idx >= 0) conf.channel_idx = p->pkt_chan_idx; if (!(p->phy_flags & PHY_FLAG_BADFCS)) { /* we can't trust any fields except phy_* of packets with bad FCS, * so we can't do all this here */ 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, 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 (!conf.quiet && !conf.debug) update_display(p); } static void local_receive_packet(int fd, unsigned char* buffer, size_t bufsize) { int len; struct packet_info p; DEBUG("\n===============================================================================\n"); len = recv_packet(fd, buffer, bufsize); #if DO_DEBUG if (conf.debug) { dump_packet(buffer, len); DEBUG("\n"); } #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); if (!conf.quiet && !conf.debug) 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); if (ctlpipe != -1) FD_SET(ctlpipe, &read_fds); tv.tv_sec = 0; tv.tv_usec = min(conf.channel_time, 1000000); mfd = max(mon, srv_fd); mfd = max(mfd, ctlpipe); 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 && !conf.debug) update_display_clock(); return; } else if (ret < 0) /* error */ err(1, "select()"); /* stdin */ if (FD_ISSET(0, &read_fds) && !conf.quiet && !conf.debug) 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)); /* named pipe */ if (ctlpipe > -1 && FD_ISSET(ctlpipe, &read_fds)) control_receive_command(); } 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_safe(&nodes, ni, mi, list) { DEBUG("free node %s\n", ether_sprintf(ni->last_pkt.wlan_src)); list_del(&ni->list); free(ni); } /* free essids */ list_for_each_safe(&essids.list, e, f, 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_safe(&spectrum[i].nodes, cn, cn2, 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); DF = NULL; } if (conf.allow_control) control_finish(); if (!conf.debug) net_finish(); if (!conf.quiet && !conf.debug) finish_display(); } static void exit_handler(void) { finish_all(); } static void sigint_handler(__attribute__((unused)) int sig) { exit(0); } static void sigpipe_handler(__attribute__((unused)) 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, "hqDsCi:t:c:p:e:f:d:o:b:X::x:m:u:a:")) > 0) { switch (c) { case 'p': conf.port = optarg; break; case 'q': conf.quiet = 1; break; case 'D': #if DO_DEBUG conf.debug = 1; #else printf("Please compile with DEBUG=1 to use the -D option!\n"); exit(1); #endif 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 'u': conf.channel_max = atoi(optarg); break; case 'X': if (optarg != NULL) conf.control_pipe = optarg; conf.allow_control = 1; break; case 'x': control_send_command(optarg); exit(0); case 'm': if (conf.filter_mode == WLAN_MODE_ALL) conf.filter_mode = 0; if (strcmp(optarg, "AP") == 0) conf.filter_mode |= WLAN_MODE_AP; else if (strcmp(optarg, "STA") == 0) conf.filter_mode |= WLAN_MODE_STA; else if (strcmp(optarg, "ADH") == 0 || strcmp(optarg, "IBSS") == 0) conf.filter_mode |= WLAN_MODE_IBSS; else if (strcmp(optarg, "PRB") == 0) conf.filter_mode |= WLAN_MODE_PROBE; else if (strcmp(optarg, "WDS") == 0) conf.filter_mode |= WLAN_MODE_4ADDR; else if (strcmp(optarg, "UNKNOWN") == 0) conf.filter_mode |= WLAN_MODE_UNKNOWN; break; case 'f': if (conf.filter_pkt == PKT_TYPE_ALL) conf.filter_pkt = 0; if (strcmp(optarg, "CTRL") == 0 || strcmp(optarg, "CONTROL") == 0) conf.filter_pkt |= PKT_TYPE_CTRL | PKT_TYPE_ALL_CTRL; else if (strcmp(optarg, "MGMT") == 0 || strcmp(optarg, "MANAGEMENT") == 0) conf.filter_pkt |= PKT_TYPE_MGMT | PKT_TYPE_ALL_MGMT; else if (strcmp(optarg, "DATA") == 0) conf.filter_pkt |= PKT_TYPE_DATA | PKT_TYPE_ALL_DATA; else if (strcmp(optarg, "BADFCS") == 0) conf.filter_pkt |= PKT_TYPE_BADFCS; else if (strcmp(optarg, "BEACON") == 0) conf.filter_pkt |= PKT_TYPE_BEACON; else if (strcmp(optarg, "PROBE") == 0) conf.filter_pkt |= PKT_TYPE_PROBE; else if (strcmp(optarg, "ASSOC") == 0) conf.filter_pkt |= PKT_TYPE_ASSOC; else if (strcmp(optarg, "AUTH") == 0) conf.filter_pkt |= PKT_TYPE_AUTH; else if (strcmp(optarg, "RTS") == 0) conf.filter_pkt |= PKT_TYPE_RTSCTS; else if (strcmp(optarg, "ACK") == 0) conf.filter_pkt |= PKT_TYPE_ACK; else if (strcmp(optarg, "NULL") == 0) conf.filter_pkt |= PKT_TYPE_NULL; else if (strcmp(optarg, "QDATA") == 0) conf.filter_pkt |= PKT_TYPE_QDATA; else if (strcmp(optarg, "ARP") == 0) conf.filter_pkt |= PKT_TYPE_ARP; else if (strcmp(optarg, "IP") == 0) conf.filter_pkt |= PKT_TYPE_IP; else if (strcmp(optarg, "ICMP") == 0) conf.filter_pkt |= PKT_TYPE_ICMP; else if (strcmp(optarg, "UDP") == 0) conf.filter_pkt |= PKT_TYPE_UDP; else if (strcmp(optarg, "TCP") == 0) conf.filter_pkt |= PKT_TYPE_TCP; else if (strcmp(optarg, "OLSR") == 0) conf.filter_pkt |= PKT_TYPE_OLSR; else if (strcmp(optarg, "BATMAN") == 0) conf.filter_pkt |= PKT_TYPE_BATMAN; else if (strcmp(optarg, "MESHZ") == 0) conf.filter_pkt |= PKT_TYPE_MESHZ; /* if one of the individual subtype frames is selected we enable the general frame type */ if (conf.filter_pkt & PKT_TYPE_ALL_MGMT) conf.filter_pkt |= PKT_TYPE_MGMT; if (conf.filter_pkt & PKT_TYPE_ALL_CTRL) conf.filter_pkt |= PKT_TYPE_CTRL; if (conf.filter_pkt & PKT_TYPE_ALL_DATA) conf.filter_pkt |= PKT_TYPE_DATA; break; case 'h': default: printf("\nUsage: %s [-h] [-q] [-D ] [-i interface] [-t sec] [-d ms] [-b bytes]\n" "\t\t[-s] [-u] [-C] [-c IP] [-p port] [-o file] [-X[name]] [-x command]\n" "\t\t[-e MAC] [-f PKT_NAME] [-m MODE]\n\n" "General Options: Description (default value)\n" " -h\t\tHelp\n" " -q\t\tQuiet, no output\n" #if DO_DEBUG " -D\t\tShow lots of debug output, no UI\n" #endif " -i \tInterface name (wlan0)\n" " -t \tNode timeout in seconds (60)\n" " -d \tDisplay update interval in ms (100)\n" " -b \tReceive buffer size in bytes (not set)\n" "\nFeature Options:\n" " -s\t\t(Poor mans) Spectrum analyzer mode\n" " -u\t\tUpper channel limit\n\n" " -C\t\tAllow client connection, server mode (off)\n" " -c \tConnect to server with , client mode (off)\n" " -p \tPort number of server (4444)\n\n" " -o \tWrite packet info into 'filename'\n\n" " -X[filename]\tAllow control socket on 'filename' (/tmp/horst)\n" " -x \tSend control command\n" "\nFilter Options:\n" " Filters are generally 'positive' or 'inclusive' which means you define\n" " what you want to see, and everything else is getting filtered out.\n" " If a filter is not set it is inactive and nothing is filtered.\n" " All filter options can be specified multiple times.\n" " -e \tSource MAC addresses (xx:xx:xx:xx:xx:xx), up to 9 times\n" " -f \tFilter packet types\n" " -m \tOperating mode: AP|STA|ADH|PRB|WDS|UNKNOWN\n" "\n", argv[0]); exit(0); break; } } } void init_spectrum(void) { int i; for (i = 0; i < conf.num_channels && i < MAX_CHANNELS; i++) { list_head_init(&spectrum[i].nodes); ewma_init(&spectrum[i].signal_avg, 1024, 8); ewma_init(&spectrum[i].durations_avg, 1024, 8); } } int main(int argc, char** argv) { list_head_init(&essids.list); list_head_init(&nodes); get_options(argc, argv); signal(SIGINT, sigint_handler); signal(SIGTERM, sigint_handler); signal(SIGHUP, sigint_handler); signal(SIGPIPE, sigpipe_handler); atexit(exit_handler); gettimeofday(&stats.stats_time, NULL); gettimeofday(&the_time, NULL); conf.channel_idx = -1; if (conf.allow_control) { printlog("Allowing control socket"); control_init_pipe(); } if (conf.serveraddr) mon = net_open_client_socket(conf.serveraddr, conf.port); else { mon = open_packet_socket(conf.ifname, conf.recv_buffer_size); if (mon <= 0) err(1, "Couldn't open packet socket"); conf.arphrd = device_get_hwinfo(mon, conf.ifname, conf.my_mac_addr); if (conf.arphrd != ARPHRD_IEEE80211_PRISM && conf.arphrd != ARPHRD_IEEE80211_RADIOTAP) { printf("You need to put your interface into monitor mode!\n"); printf("(e.g. 'iw %s interface add mon0 type monitor' and 'horst -i mon0')\n", conf.ifname); exit(1); } channel_init(); init_spectrum(); } if (!conf.quiet && !conf.debug) init_display(); if (conf.dumpfile != NULL) dumpfile_open(conf.dumpfile); 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 (channel_auto_change()) { net_send_channel_config(); update_spectrum_durations(); if (!conf.quiet && !conf.debug) update_display(NULL); } } } /* will never */ return 0; } void main_pause(int pause) { conf.paused = pause; printlog(conf.paused ? "- PAUSED -" : "- RESUME -"); } void dumpfile_open(char* name) { if (DF != NULL) { fclose(DF); DF = NULL; } if (name == NULL || strlen(name) == 0) { printlog("- Not writing outfile"); conf.dumpfile = NULL; return; } conf.dumpfile = name; DF = fopen(conf.dumpfile, "w"); if (DF == NULL) err(1, "Couldn't open dump file"); printlog("- Writing to outfile %s", conf.dumpfile); } #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-4.2/main.h000066400000000000000000000224101241274412600136150ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 #include #include "ccan/list/list.h" #include "average.h" #include "channel.h" #include "wlan80211.h" #define VERSION "4.2" #ifndef DO_DEBUG #define DO_DEBUG 0 #endif #if DO_DEBUG #define DEBUG(...) do { if (conf.debug) printf(__VA_ARGS__); } while (0) #else #define DEBUG(...) #endif #define MAC_LEN 6 #define MAX_HISTORY 255 #define MAX_RATES 44 /* 12 legacy rates and 32 MCS */ #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_BADFCS 0x000008 #define PKT_TYPE_BEACON 0x000010 #define PKT_TYPE_PROBE 0x000020 #define PKT_TYPE_ASSOC 0x000040 #define PKT_TYPE_AUTH 0x000080 #define PKT_TYPE_RTSCTS 0x000100 #define PKT_TYPE_ACK 0x000200 #define PKT_TYPE_NULL 0x000400 #define PKT_TYPE_QDATA 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_BATMAN 0x040000 #define PKT_TYPE_MESHZ 0x080000 #define PKT_TYPE_ALL_MGMT (PKT_TYPE_BEACON | PKT_TYPE_PROBE | PKT_TYPE_ASSOC | PKT_TYPE_AUTH) #define PKT_TYPE_ALL_CTRL (PKT_TYPE_RTSCTS | PKT_TYPE_ACK) #define PKT_TYPE_ALL_DATA (PKT_TYPE_NULL | PKT_TYPE_QDATA | PKT_TYPE_ARP | PKT_TYPE_ICMP | PKT_TYPE_IP | \ PKT_TYPE_UDP | PKT_TYPE_TCP | PKT_TYPE_OLSR | PKT_TYPE_BATMAN | PKT_TYPE_MESHZ) #define PKT_TYPE_ALL (PKT_TYPE_CTRL | PKT_TYPE_MGMT | PKT_TYPE_DATA | PKT_TYPE_ALL_MGMT | PKT_TYPE_ALL_CTRL | PKT_TYPE_ALL_DATA | PKT_TYPE_BADFCS) #define WLAN_MODE_AP 0x01 #define WLAN_MODE_IBSS 0x02 #define WLAN_MODE_STA 0x04 #define WLAN_MODE_PROBE 0x08 #define WLAN_MODE_4ADDR 0x10 #define WLAN_MODE_UNKNOWN 0x20 #define WLAN_MODE_ALL (WLAN_MODE_AP | WLAN_MODE_IBSS | WLAN_MODE_STA | WLAN_MODE_PROBE | WLAN_MODE_4ADDR | WLAN_MODE_UNKNOWN) #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() */ #define DEFAULT_CONTROL_PIPE "/tmp/horst" #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) */ unsigned int phy_rate; /* physical rate * 10 (=in 100kbps) */ unsigned char phy_rate_idx; /* MCS index */ unsigned char phy_rate_flags; /* MCS flags */ unsigned int phy_freq; /* frequency from driver */ unsigned int phy_flags; /* A, B, G, shortpre */ /* wlan mac */ unsigned int wlan_len; /* packet length */ u_int16_t wlan_type; /* frame control field */ unsigned char wlan_src[MAC_LEN]; /* transmitter (TA) */ unsigned char wlan_dst[MAC_LEN]; /* receiver (RA) */ unsigned char wlan_bssid[MAC_LEN]; char wlan_essid[WLAN_MAX_SSID_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, wlan_wpa:1, wlan_rsn:1; /* batman-adv */ unsigned char bat_version; unsigned char bat_packet_type; unsigned char bat_gw: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_node list; struct list_node 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_sig_max; struct ewma phy_sig_avg; unsigned long phy_sig_sum; int phy_sig_count; /* 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; struct node_info* wlan_ap_node; unsigned int wlan_wep:1, /* WEP active? */ wlan_wpa:1, wlan_rsn:1; /* batman */ unsigned char bat_gw:1; /* 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_node list; char essid[WLAN_MAX_SSID_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 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; struct channel_info { int signal; struct ewma signal_avg; 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_node chan_list; /* list for nodes per channel */ struct list_node 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 channel_idx; /* index into channels array */ int display_interval; char* dumpfile; int recv_buffer_size; char* serveraddr; char* control_pipe; unsigned char filtermac[MAX_FILTERMAC][MAC_LEN]; char filtermac_enabled[MAX_FILTERMAC]; unsigned char filterbssid[MAC_LEN]; unsigned int filter_pkt; unsigned int filter_mode; unsigned int filter_off:1, do_change_channel:1, allow_client:1, allow_control:1, debug:1, /* this isn't exactly config, but wtf... */ do_macfilter:1, display_initialized:1; int arphrd; // the device ARP type unsigned char my_mac_addr[MAC_LEN]; int paused; int num_channels; }; extern struct config conf; extern struct timeval the_time; void free_lists(void); void init_spectrum(void); void update_spectrum_durations(void); void handle_packet(struct packet_info* p); void __attribute__ ((format (printf, 1, 2))) printlog(const char *fmt, ...); void main_pause(int pause); void dumpfile_open(char* name); #endif horst-4.2/network.c000066400000000000000000000354711241274412600143700ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 "channel.h" #include "network.h" extern struct config conf; int srv_fd = -1; int cli_fd = -1; static int netmon_fd; #define PROTO_VERSION 2 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; int filter_mode; unsigned char filter_off; } __attribute__ ((packed)); struct net_chan_freq { unsigned char chan; unsigned int freq; } __attribute__ ((packed)); struct net_chan_list { struct net_header proto; unsigned char num_channels; struct net_chan_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 (always 0) */ unsigned int phy_snr; /* signal to noise ratio (always 0, redundant!) */ unsigned int phy_rate; /* physical rate * 10 (= in 100kbps) */ unsigned int phy_freq; /* frequency */ 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[WLAN_MAX_SSID_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 #define PKT_WLAN_FLAG_WPA 0x4 #define PKT_WLAN_FLAG_RSN 0x8 /* 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; #define PKT_BAT_FLAG_GW 0x1 unsigned char bat_flags; unsigned char bat_pkt_type; unsigned char phy_rate_idx; unsigned char phy_rate_flags; } __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(0); np.phy_snr = htole32(0); np.phy_rate = htole32(p->phy_rate); np.phy_rate_idx = p->phy_rate_idx; np.phy_rate_flags = p->phy_rate_flags; np.phy_freq = htole32(p->phy_freq); 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, WLAN_MAX_SSID_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; if (p->wlan_wpa) np.wlan_flags |= PKT_WLAN_FLAG_WPA; if (p->wlan_rsn) np.wlan_flags |= PKT_WLAN_FLAG_RSN; 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); np.bat_flags = 0; if (p->bat_gw) np.bat_flags |= PKT_BAT_FLAG_GW; np.bat_pkt_type = p->bat_packet_type; net_write(cli_fd, (unsigned char *)&np, sizeof(np)); return 0; } static int net_receive_packet(unsigned char *buffer, size_t 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_rate = le32toh(np->phy_rate); p.phy_rate_idx = np->phy_rate_idx; p.phy_rate_flags= np->phy_rate_flags; p.phy_freq = le32toh(np->phy_freq); 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, WLAN_MAX_SSID_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; if (np->wlan_flags & PKT_WLAN_FLAG_WPA) p.wlan_wpa = 1; if (np->wlan_flags & PKT_WLAN_FLAG_RSN) p.wlan_rsn = 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); if (np->bat_flags & PKT_BAT_FLAG_GW) p.bat_gw = 1; p.bat_packet_type = np->bat_pkt_type; handle_packet(&p); return sizeof(struct net_packet_info); } static 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.channel_idx; nc.dwell_time = htole32(conf.channel_time); net_write(fd, (unsigned char *)&nc, sizeof(nc)); } static int net_receive_conf_chan(unsigned char *buffer, size_t 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.channel_idx) /* server */ channel_change(nc->channel); else { /* client */ conf.channel_idx = nc->channel; update_spectrum_durations(); } return sizeof(struct net_conf_chan); } static 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_mode = htole32(conf.filter_mode); 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, size_t 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_mode = le32toh(nc->filter_mode); 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) + sizeof(struct net_chan_freq)*(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++) { struct chan_freq* cf = channel_get_struct(i); if (cf != NULL) { nc->channel[i].chan = cf->chan; nc->channel[i].freq = htole32(cf->freq); DEBUG("NET send chan %d %d %d\n", i, cf->chan, cf->freq); } else { printlog("NET send chan ERR"); } } nc->num_channels = i; net_write(fd, (unsigned char *)buf, sizeof(struct net_chan_list) + sizeof(struct net_chan_freq)*(i - 1)); free(buf); return 0; } static int net_receive_chan_list(unsigned char *buffer, size_t 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) + sizeof(struct net_chan_freq)*(nc->num_channels - 1)) return 0; if (nc->num_channels > MAX_CHANNELS) { printlog("ERR: server sent too many channels, truncated"); conf.num_channels = MAX_CHANNELS; } else { conf.num_channels = nc->num_channels; } for (i = 0; i < conf.num_channels; i++) { channel_set(i, nc->channel[i].chan, le32toh(nc->channel[i].freq)); DEBUG("NET recv chan %d %d %d\n", i, nc->channel[i].chan, le32toh(nc->channel[i].freq)); } init_spectrum(); return sizeof(struct net_chan_list) + sizeof(struct net_chan_freq)*(nc->num_channels - 1); } static int try_receive_packet(unsigned char* buf, size_t 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-4.2/network.h000066400000000000000000000024761241274412600143740ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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_ #include 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-4.2/node.c000066400000000000000000000117411241274412600136160ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 "wlan80211.h" #include "essid.h" static struct timeval last_nodetimeout; static void copy_nodeinfo(struct node_info* n, struct packet_info* p) { struct node_info* ap; 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->bat_gw) n->bat_gw = 1; 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 ((n->wlan_mode & WLAN_MODE_STA) && n->wlan_ap_node == NULL) { /* find AP node for this BSSID */ list_for_each(&nodes, ap, list) { if (memcmp(p->wlan_bssid, ap->last_pkt.wlan_src, MAC_LEN) == 0) { DEBUG("AP node found %p\n", ap); DEBUG("AP node ESSID %s\n", ap->essid != NULL ? ap->essid->essid : "unknown"); n->wlan_ap_node = ap; break; } } n->wlan_rsn = ap->wlan_rsn; n->wlan_wpa = ap->wlan_wpa; } } if ((p->wlan_type == WLAN_FRAME_BEACON) || (p->wlan_type == WLAN_FRAME_PROBE_RESP)) { n->wlan_tsf = p->wlan_tsf; n->wlan_bintval = p->wlan_bintval; n->wlan_wpa = p->wlan_wpa; n->wlan_rsn = p->wlan_rsn; } ewma_add(&n->phy_sig_avg, -p->phy_signal); n->phy_sig_sum += -p->phy_signal; n->phy_sig_count += 1; if (p->phy_signal > n->phy_sig_max || n->phy_sig_max == 0) n->phy_sig_max = p->phy_signal; if (p->wlan_channel != 0) n->wlan_channel = p->wlan_channel; if ((p->wlan_type == WLAN_FRAME_DATA) || (p->wlan_type == WLAN_FRAME_QDATA) || (p->wlan_type == WLAN_FRAME_AUTH) || (p->wlan_type == WLAN_FRAME_BEACON) || (p->wlan_type == WLAN_FRAME_PROBE_RESP) || (p->wlan_type == WLAN_FRAME_DATA_CF_ACK) || (p->wlan_type == WLAN_FRAME_DATA_CF_POLL) || (p->wlan_type == WLAN_FRAME_DATA_CF_ACKPOLL) || (p->wlan_type == WLAN_FRAME_QDATA_CF_ACK) || (p->wlan_type == WLAN_FRAME_QDATA_CF_POLL) || (p->wlan_type == WLAN_FRAME_QDATA_CF_ACKPOLL)) 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->phy_flags & PHY_FLAG_BADFCS) return NULL; 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(&nodes, n, 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.n) { DEBUG("node adding\n"); n = malloc(sizeof(struct node_info)); memset(n, 0, sizeof(struct node_info)); n->essid = NULL; ewma_init(&n->phy_sig_avg, 1024, 8); list_head_init(&n->on_channels); list_add_tail(&nodes, &n->list); } copy_nodeinfo(n, p); return n; } void timeout_nodes(void) { struct node_info *n, *m, *n2, *m2; struct chan_node *cn, *cn2; if ((the_time.tv_sec - last_nodetimeout.tv_sec) < conf.node_timeout ) return; list_for_each_safe(&nodes, n, m, 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_safe(&n->on_channels, cn, cn2, node_list) { list_del(&cn->node_list); list_del(&cn->chan_list); cn->chan->num_nodes--; free(cn); } /* remove AP pointers to this node */ list_for_each_safe(&nodes, n2, m2, list) { if (n2->wlan_ap_node == n) { DEBUG("remove AP ref\n"); n->wlan_ap_node = NULL; } } free(n); } } last_nodetimeout = the_time; } horst-4.2/node.h000066400000000000000000000017001241274412600136150ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 _NODE_H_ #define _NODE_H_ struct node_info* node_update(struct packet_info* p); void timeout_nodes(void); #endif horst-4.2/olsr_header.h000066400000000000000000000123401241274412600151610ustar00rootroot00000000000000/* 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-4.2/prism_header.h000066400000000000000000000057541241274412600153470ustar00rootroot00000000000000/* 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-4.2/protocol_parser.c000066400000000000000000000173551241274412600161150ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 #define __FAVOR_BSD #include #include "olsr_header.h" #include "batman_header.h" #include "batman_adv_header-14.h" #include "main.h" #include "util.h" extern int parse_packet_wlan(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_batman_adv_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) { len = parse_packet_wlan(&buf, len, p); if (len == 0) return 1; else if (len < 0) return 0; 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_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 (ntohs(*((uint16_t*)*buf)) == 0x4305) { DEBUG("BATMAN-ADV\n"); (*buf)++; (*buf)++; return parse_batman_adv_packet(buf, len - 8, p); } else { 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_batman_adv_packet(unsigned char** buf, int len, struct packet_info* p) { struct batman_ogm_packet *bp; //batadv_ogm_packet bp = (struct batman_ogm_packet*)*buf; p->pkt_types |= PKT_TYPE_BATMAN; p->bat_version = bp->version; p->bat_packet_type = bp->packet_type; DEBUG("parse bat len %d type %d vers %d\n", len, bp->packet_type, bp->version); /* version 14 */ if (bp->version == 14) { switch (bp->packet_type) { case BAT_OGM: /* set GW flags only for "original" (not re-sent) OGMs */ if (bp->gw_flags != 0 && memcmp(bp->orig, p->wlan_src, MAC_LEN) == 0) p->bat_gw = 1; DEBUG("OGM %d %d\n", bp->gw_flags, p->bat_gw); return 0; case BAT_ICMP: DEBUG("ICMP\n"); break; case BAT_UNICAST: DEBUG("UNI %zu\n", sizeof(struct unicast_packet)); *buf = *buf + sizeof(struct unicast_packet) + 14; return len - sizeof(struct unicast_packet) - 14; case BAT_BCAST: DEBUG("BCAST\n"); break; case BAT_VIS: case BAT_UNICAST_FRAG: case BAT_TT_QUERY: case BAT_ROAM_ADV: break; } } return 0; } static int parse_ip_header(unsigned char** buf, int len, struct packet_info* p) { struct ip* ih; DEBUG("* parse IP\n"); if (len > 0 && (size_t)len < sizeof(struct ip)) return -1; ih = (struct ip*)*buf; DEBUG("*** IP SRC: %s\n", ip_sprintf(ih->ip_src.s_addr)); DEBUG("*** IP DST: %s\n", ip_sprintf(ih->ip_dst.s_addr)); p->ip_src = ih->ip_src.s_addr; p->ip_dst = ih->ip_dst.s_addr; p->pkt_types |= PKT_TYPE_IP; DEBUG("IP proto: %d\n", ih->ip_p); switch (ih->ip_p) { 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->ip_hl * 4; return len - ih->ip_hl * 4; } static int parse_udp_header(unsigned char** buf, int len, struct packet_info* p) { struct udphdr* uh; if (len > 0 && (size_t)len < sizeof(struct udphdr)) return -1; uh = (struct udphdr*)*buf; DEBUG("UPD dest port: %d\n", ntohs(uh->uh_dport)); p->tcpudp_port = ntohs(uh->uh_dport); *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, msgtype; if (len > 0 && (size_t)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; } 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; } } #endif /* done for good */ return 0; } static int parse_batman_packet(__attribute__((unused)) unsigned char** buf, __attribute__((unused)) int len, __attribute__((unused)) struct packet_info* p) { p->pkt_types |= PKT_TYPE_BATMAN; return 0; } static int parse_meshcruzer_packet(__attribute__((unused)) unsigned char** buf, __attribute__((unused)) int len, __attribute__((unused)) struct packet_info* p, __attribute__((unused)) int port) { p->pkt_types |= PKT_TYPE_MESHZ; return 0; } horst-4.2/protocol_parser.h000066400000000000000000000017411241274412600161120ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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-4.2/protocol_parser_wlan.c000066400000000000000000000342541241274412600171330ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 "prism_header.h" #include "radiotap/radiotap.h" #include "radiotap/radiotap_iter.h" #include "wlan80211.h" #include "wlan_util.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); /* return rest of packet length (may be 0) or negative value on error */ int parse_packet_wlan(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 -1; } else if (conf.arphrd == ARPHRD_IEEE80211_RADIOTAP) { len = parse_radiotap_header(buf, len, p); if (len <= 0) {/* 0: Bad FCS, allow packet but stop parsing */ DEBUG("A"); return len; } } DEBUG("before parse 80211 len: %d\n", len); return parse_80211_header(buf, len, p); } /* return packet lenght or -1 on error */ 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 > 0 && (size_t)len < sizeof(wlan_ng_prism2_header)) return -1; ph = (wlan_ng_prism2_header*)*buf; /* * different drivers report S/N and rssi values differently */ if (((int)ph->noise.data) < 0) { /* new madwifi */ p->phy_signal = ph->signal.data; } else if (((int)ph->rssi.data) < 0) { /* broadcom hack */ p->phy_signal = ph->rssi.data; } else { /* assume hostap */ p->phy_signal = ph->signal.data; } p->phy_rate = ph->rate.data * 10; /* just in case...*/ if (p->phy_rate == 0 || p->phy_rate > 1080) { /* assume min rate, guess mode from channel */ DEBUG("*** fixing wrong rate\n"); if (ph->channel.data > 14) p->phy_rate = 120; /* 6 * 2 */ else p->phy_rate = 20; /* 1 * 2 */ } p->phy_rate_idx = rate_to_index(p->phy_rate); /* 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("rate: %d\n", ph->rate.data); DEBUG("rssi: %d\n", ph->rssi.data); *buf = *buf + sizeof(wlan_ng_prism2_header); return len - sizeof(wlan_ng_prism2_header); } static void get_radiotap_info(struct ieee80211_radiotap_iterator *iter, struct packet_info* p) { uint16_t x; signed char c; unsigned char known, flags, ht20, lgi; switch (iter->this_arg_index) { /* ignoring these */ case IEEE80211_RADIOTAP_TSFT: case IEEE80211_RADIOTAP_FHSS: case IEEE80211_RADIOTAP_LOCK_QUALITY: case IEEE80211_RADIOTAP_TX_ATTENUATION: case IEEE80211_RADIOTAP_DB_TX_ATTENUATION: case IEEE80211_RADIOTAP_DBM_TX_POWER: case IEEE80211_RADIOTAP_TX_FLAGS: case IEEE80211_RADIOTAP_RX_FLAGS: case IEEE80211_RADIOTAP_RTS_RETRIES: case IEEE80211_RADIOTAP_DATA_RETRIES: case IEEE80211_RADIOTAP_AMPDU_STATUS: break; case IEEE80211_RADIOTAP_FLAGS: /* short preamble */ DEBUG("[flags %0x", *iter->this_arg); if (*iter->this_arg & IEEE80211_RADIOTAP_F_SHORTPRE) { p->phy_flags |= PHY_FLAG_SHORTPRE; DEBUG(" shortpre"); } if (*iter->this_arg & IEEE80211_RADIOTAP_F_BADFCS) { p->phy_flags |= PHY_FLAG_BADFCS; p->pkt_types |= PKT_TYPE_BADFCS; DEBUG(" badfcs"); } DEBUG("]"); break; case IEEE80211_RADIOTAP_RATE: //TODO check! //printf("\trate: %lf\n", (double)*iter->this_arg/2); DEBUG("[rate %0x]", *iter->this_arg); p->phy_rate = (*iter->this_arg)*5; /* rate is in 500kbps */ p->phy_rate_idx = rate_to_index(p->phy_rate); break; #define IEEE80211_CHAN_A \ (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM) #define IEEE80211_CHAN_G \ (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM) case IEEE80211_RADIOTAP_CHANNEL: /* channel & channel type */ p->phy_freq = le16toh(*(uint16_t*)iter->this_arg); DEBUG("[freq %d", p->phy_freq); iter->this_arg = iter->this_arg + 2; x = le16toh(*(uint16_t*)iter->this_arg); if ((x & IEEE80211_CHAN_A) == IEEE80211_CHAN_A) { p->phy_flags |= PHY_FLAG_A; DEBUG("A]"); } else if ((x & IEEE80211_CHAN_G) == IEEE80211_CHAN_G) { p->phy_flags |= PHY_FLAG_G; DEBUG("G]"); } else if ((x & IEEE80211_CHAN_2GHZ) == IEEE80211_CHAN_2GHZ) { p->phy_flags |= PHY_FLAG_B; DEBUG("B]"); } break; case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: c = *(signed char*)iter->this_arg; DEBUG("[sig %0d]", c); /* we get the signal per rx chain with newer drivers. * save the highest value, but make sure we don't override * with invalid values */ if (c < 0 && (p->phy_signal == 0 || c > p->phy_signal)) p->phy_signal = c; break; case IEEE80211_RADIOTAP_DBM_ANTNOISE: DEBUG("[noi %0x]", *(signed char*)iter->this_arg); // usually not present //p->phy_noise = *(signed char*)iter->this_arg; break; case IEEE80211_RADIOTAP_ANTENNA: DEBUG("[ant %0x]", *iter->this_arg); break; case IEEE80211_RADIOTAP_DB_ANTSIGNAL: DEBUG("[snr %0x]", *iter->this_arg); // usually not present //p->phy_snr = *iter->this_arg; break; case IEEE80211_RADIOTAP_DB_ANTNOISE: //printf("\tantnoise: %02d\n", *iter->this_arg); break; case IEEE80211_RADIOTAP_MCS: /* Ref http://www.radiotap.org/defined-fields/MCS */ known = *iter->this_arg++; flags = *iter->this_arg++; DEBUG("[MCS known %0x flags %0x index %0x]", known, flags, *iter->this_arg); if (known & IEEE80211_RADIOTAP_MCS_HAVE_BW) ht20 = (flags & IEEE80211_RADIOTAP_MCS_BW_MASK) == IEEE80211_RADIOTAP_MCS_BW_20; else ht20 = 1; /* assume HT20 if not present */ if (known & IEEE80211_RADIOTAP_MCS_HAVE_GI) lgi = !(flags & IEEE80211_RADIOTAP_MCS_SGI); else lgi = 1; /* assume long GI if not present */ DEBUG(" %s %s", ht20 ? "HT20" : "HT40", lgi ? "LGI" : "SGI"); p->phy_rate_idx = 12 + *iter->this_arg; p->phy_rate_flags = flags; p->phy_rate = mcs_index_to_rate(*iter->this_arg, ht20, lgi); DEBUG(" RATE %d ", p->phy_rate); break; default: printlog("UNKNOWN RADIOTAP field %d", iter->this_arg_index); break; } } /* return length of packet, 0 for bad FCS, -1 on error */ static int parse_radiotap_header(unsigned char** buf, int len, struct packet_info* p) { struct ieee80211_radiotap_header* rh; struct ieee80211_radiotap_iterator iter; int err, rt_len; rh = (struct ieee80211_radiotap_header*)*buf; rt_len = le16toh(rh->it_len); err = ieee80211_radiotap_iterator_init(&iter, rh, rt_len, NULL); if (err) { DEBUG("malformed radiotap header (init returns %d)\n", err); return -1; } DEBUG("Radiotap: "); while (!(err = ieee80211_radiotap_iterator_next(&iter))) { if (iter.is_radiotap_ns) { get_radiotap_info(&iter, p); } } DEBUG("\nSIG %d", p->phy_signal); /* sanitize */ if (p->phy_rate == 0 || p->phy_rate > 6000) { /* assume min rate for mode */ DEBUG("*** fixing wrong rate\n"); if (p->phy_flags & PHY_FLAG_A) p->phy_rate = 120; /* 6 * 2 */ else if (p->phy_flags & PHY_FLAG_B) p->phy_rate = 20; /* 1 * 2 */ else if (p->phy_flags & PHY_FLAG_G) p->phy_rate = 120; /* 6 * 2 */ else p->phy_rate = 20; } DEBUG("\nrate: %.2f = idx %d\n", (float)p->phy_rate/10, p->phy_rate_idx); DEBUG("signal: %d\n", p->phy_signal); if (p->phy_flags & PHY_FLAG_BADFCS) { /* we can't trust frames with a bad FCS - stop parsing */ DEBUG("=== bad FCS, stop ===\n"); return 0; } else { *buf = *buf + rt_len; return len - rt_len; } } /* return rest of packet length (may be 0) or -1 on error */ static int parse_80211_header(unsigned char** buf, int len, struct packet_info* p) { struct wlan_frame* wh; int hdrlen; u_int8_t* ra = NULL; u_int8_t* ta = NULL; u_int8_t* bssid = NULL; u_int16_t fc, cap_i; if (len < 10) /* minimum frame size (CTS/ACK) */ return -1; p->wlan_mode = WLAN_MODE_UNKNOWN; wh = (struct wlan_frame*)*buf; fc = le16toh(wh->fc); p->wlan_type = (fc & WLAN_FRAME_FC_MASK); DEBUG("wlan_type %x - type %x - stype %x\n", fc, fc & WLAN_FRAME_FC_TYPE_MASK, fc & WLAN_FRAME_FC_STYPE_MASK); DEBUG("%s\n", get_packet_type_name(fc)); if (WLAN_FRAME_IS_DATA(fc)) { p->pkt_types |= PKT_TYPE_DATA; hdrlen = 24; if (WLAN_FRAME_IS_QOS(fc)) { hdrlen += 2; if (fc & WLAN_FRAME_FC_ORDER) hdrlen += 4; } /* AP, STA or IBSS */ if ((fc & WLAN_FRAME_FC_FROM_DS) == 0 && (fc & WLAN_FRAME_FC_TO_DS) == 0) { p->wlan_mode = WLAN_MODE_IBSS; bssid = wh->addr3; } else if ((fc & WLAN_FRAME_FC_FROM_DS) && (fc & WLAN_FRAME_FC_TO_DS)) { p->wlan_mode = WLAN_MODE_4ADDR; hdrlen += 6; if (WLAN_FRAME_IS_QOS(fc)) { u_int16_t qos = le16toh(wh->u.addr4_qos_ht.qos); DEBUG("4ADDR A-MSDU %x\n", qos & WLAN_FRAME_QOS_AMSDU_PRESENT); if (qos & WLAN_FRAME_QOS_AMSDU_PRESENT) bssid = wh->addr3; // in the MSDU case BSSID is unknown } } else if (fc & WLAN_FRAME_FC_FROM_DS) { p->wlan_mode = WLAN_MODE_AP; bssid = wh->addr2; } else if (fc & WLAN_FRAME_FC_TO_DS) { p->wlan_mode = WLAN_MODE_STA; bssid = wh->addr1; } if (len < hdrlen) return -1; p->wlan_nav = le16toh(wh->duration); DEBUG("DATA NAV %d\n", p->wlan_nav); p->wlan_seqno = le16toh(wh->seq); DEBUG("DATA SEQ %d\n", p->wlan_seqno); DEBUG("A1 %s\n", ether_sprintf(wh->addr1)); DEBUG("A2 %s\n", ether_sprintf(wh->addr2)); DEBUG("A3 %s\n", ether_sprintf(wh->addr3)); if (p->wlan_mode == WLAN_MODE_4ADDR) { DEBUG("A4 %s\n", ether_sprintf(wh->u.addr4)); } DEBUG("ToDS %d FromDS %d\n", (fc & WLAN_FRAME_FC_FROM_DS) != 0, (fc & WLAN_FRAME_FC_TO_DS) != 0); ra = wh->addr1; ta = wh->addr2; /* WEP */ if (fc & WLAN_FRAME_FC_PROTECTED) p->wlan_wep = 1; if (fc & WLAN_FRAME_FC_RETRY) p->wlan_retry = 1; } else if (WLAN_FRAME_IS_CTRL(fc)) { p->pkt_types |= PKT_TYPE_CTRL; if (p->wlan_type == WLAN_FRAME_CTS || p->wlan_type == WLAN_FRAME_ACK) hdrlen = 10; else hdrlen = 16; if (len < hdrlen) return -1; } else if (WLAN_FRAME_IS_MGMT(fc)) { p->pkt_types |= PKT_TYPE_MGMT; hdrlen = 24; if (fc & WLAN_FRAME_FC_ORDER) hdrlen += 4; if (len < hdrlen) return -1; ra = wh->addr1; ta = wh->addr2; bssid = wh->addr3; p->wlan_seqno = le16toh(wh->seq); DEBUG("MGMT SEQ %d\n", p->wlan_seqno); if (fc & WLAN_FRAME_FC_RETRY) p->wlan_retry = 1; } else { DEBUG("!!!UNKNOWN FRAME!!!"); return -1; } p->wlan_len = len; switch (p->wlan_type) { case WLAN_FRAME_NULL: p->pkt_types |= PKT_TYPE_NULL; break; case WLAN_FRAME_QDATA: p->pkt_types |= PKT_TYPE_QDATA; p->wlan_qos_class = le16toh(wh->u.qos) & WLAN_FRAME_QOS_TID_MASK; DEBUG("***QDATA %x\n", p->wlan_qos_class); break; case WLAN_FRAME_RTS: p->pkt_types |= PKT_TYPE_RTSCTS; p->wlan_nav = le16toh(wh->duration); DEBUG("RTS NAV %d\n", p->wlan_nav); ra = wh->addr1; ta = wh->addr2; break; case WLAN_FRAME_CTS: p->pkt_types |= PKT_TYPE_RTSCTS; p->wlan_nav = le16toh(wh->duration); DEBUG("CTS NAV %d\n", p->wlan_nav); ra = wh->addr1; break; case WLAN_FRAME_ACK: p->pkt_types |= PKT_TYPE_ACK; p->wlan_nav = le16toh(wh->duration); DEBUG("ACK NAV %d\n", p->wlan_nav); ra = wh->addr1; break; case WLAN_FRAME_PSPOLL: ra = wh->addr1; bssid = wh->addr1; ta = wh->addr2; break; case WLAN_FRAME_CF_END: case WLAN_FRAME_CF_END_ACK: ra = wh->addr1; ta = wh->addr2; bssid = wh->addr2; break; case WLAN_FRAME_BLKACK: case WLAN_FRAME_BLKACK_REQ: p->pkt_types |= PKT_TYPE_ACK; p->wlan_nav = le16toh(wh->duration); ra = wh->addr1; ta = wh->addr2; break; case WLAN_FRAME_BEACON: case WLAN_FRAME_PROBE_RESP: if (p->wlan_type == WLAN_FRAME_BEACON) p->pkt_types |= PKT_TYPE_BEACON; else p->pkt_types |= PKT_TYPE_PROBE; struct wlan_frame_beacon* bc = (struct wlan_frame_beacon*)(*buf + hdrlen); p->wlan_tsf = le64toh(bc->tsf); p->wlan_bintval = le16toh(bc->bintval); //DEBUG("TSF %u\n BINTVAL %u", p->wlan_tsf, p->wlan_bintval); wlan_parse_information_elements(bc->ie, len - hdrlen - sizeof(struct wlan_frame_beacon) - 4 /* FCS */, p); DEBUG("ESSID %s \n", p->wlan_essid ); DEBUG("CHAN %d \n", p->wlan_channel ); cap_i = le16toh(bc->capab); if (cap_i & WLAN_CAPAB_IBSS) p->wlan_mode = WLAN_MODE_IBSS; else if (cap_i & WLAN_CAPAB_ESS) p->wlan_mode = WLAN_MODE_AP; if (cap_i & WLAN_CAPAB_PRIVACY) p->wlan_wep = 1; break; case WLAN_FRAME_PROBE_REQ: p->pkt_types |= PKT_TYPE_PROBE; wlan_parse_information_elements((*buf + hdrlen), len - hdrlen - 4 /* FCS */, p); p->wlan_mode = WLAN_MODE_PROBE; break; case WLAN_FRAME_ASSOC_REQ: case WLAN_FRAME_ASSOC_RESP: case WLAN_FRAME_REASSOC_REQ: case WLAN_FRAME_REASSOC_RESP: case WLAN_FRAME_DISASSOC: p->pkt_types |= PKT_TYPE_ASSOC; break; case WLAN_FRAME_AUTH: if (fc & WLAN_FRAME_FC_PROTECTED) p->wlan_wep = 1; /* no break */ case WLAN_FRAME_DEAUTH: p->pkt_types |= PKT_TYPE_AUTH; break; case WLAN_FRAME_ACTION: break; } if (ta != NULL) { memcpy(p->wlan_src, ta, MAC_LEN); DEBUG("TA %s\n", ether_sprintf(ta)); } if (ra != NULL) { memcpy(p->wlan_dst, ra, MAC_LEN); DEBUG("RA %s\n", ether_sprintf(ra)); } 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 (WLAN_FRAME_IS_DATA(p->wlan_type) && p->wlan_wep != 1) { *buf = *buf + hdrlen; return len - hdrlen; } return 0; } horst-4.2/radiotap/000077500000000000000000000000001241274412600143245ustar00rootroot00000000000000horst-4.2/radiotap/COPYING000066400000000000000000000014641241274412600153640ustar00rootroot00000000000000Copyright (c) 2007-2009 Andy Green Copyright (c) 2007-2009 Johannes Berg Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. horst-4.2/radiotap/platform.h000066400000000000000000000007141241274412600163230ustar00rootroot00000000000000#include #include #include "../util.h" #define le16_to_cpu le16toh #define le32_to_cpu le32toh #define get_unaligned(p) \ ({ \ struct packed_dummy_struct { \ typeof(*(p)) __val; \ } __attribute__((packed)) *__ptr = (void *) (p); \ \ __ptr->__val; \ }) #define get_unaligned_le16(p) le16_to_cpu(get_unaligned((uint16_t *)(p))) #define get_unaligned_le32(p) le32_to_cpu(get_unaligned((uint32_t *)(p))) horst-4.2/radiotap/radiotap.c000066400000000000000000000302351241274412600162760ustar00rootroot00000000000000/* * Radiotap parser * * Copyright 2007 Andy Green * Copyright 2009 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. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See COPYING for more details. */ #include "radiotap_iter.h" #include "platform.h" /* function prototypes and related defs are in radiotap_iter.h */ static const struct radiotap_align_size rtap_namespace_sizes[] = { [IEEE80211_RADIOTAP_TSFT] = { .align = 8, .size = 8, }, [IEEE80211_RADIOTAP_FLAGS] = { .align = 1, .size = 1, }, [IEEE80211_RADIOTAP_RATE] = { .align = 1, .size = 1, }, [IEEE80211_RADIOTAP_CHANNEL] = { .align = 2, .size = 4, }, [IEEE80211_RADIOTAP_FHSS] = { .align = 2, .size = 2, }, [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = { .align = 1, .size = 1, }, [IEEE80211_RADIOTAP_DBM_ANTNOISE] = { .align = 1, .size = 1, }, [IEEE80211_RADIOTAP_LOCK_QUALITY] = { .align = 2, .size = 2, }, [IEEE80211_RADIOTAP_TX_ATTENUATION] = { .align = 2, .size = 2, }, [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = { .align = 2, .size = 2, }, [IEEE80211_RADIOTAP_DBM_TX_POWER] = { .align = 1, .size = 1, }, [IEEE80211_RADIOTAP_ANTENNA] = { .align = 1, .size = 1, }, [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = { .align = 1, .size = 1, }, [IEEE80211_RADIOTAP_DB_ANTNOISE] = { .align = 1, .size = 1, }, [IEEE80211_RADIOTAP_RX_FLAGS] = { .align = 2, .size = 2, }, [IEEE80211_RADIOTAP_TX_FLAGS] = { .align = 2, .size = 2, }, [IEEE80211_RADIOTAP_RTS_RETRIES] = { .align = 1, .size = 1, }, [IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, }, [IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, }, [IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, }, /* * add more here as they are defined in radiotap.h */ }; static const struct ieee80211_radiotap_namespace radiotap_ns = { .n_bits = sizeof(rtap_namespace_sizes) / sizeof(rtap_namespace_sizes[0]), .align_size = rtap_namespace_sizes, }; /** * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization * @iterator: radiotap_iterator to initialize * @radiotap_header: radiotap header to parse * @max_length: total length we can parse into (eg, whole packet length) * * Returns: 0 or a negative error code if there is a problem. * * This function initializes an opaque iterator struct which can then * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap * argument which is present in the header. It knows about extended * present headers and handles them. * * How to use: * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) * checking for a good 0 return code. Then loop calling * __ieee80211_radiotap_iterator_next()... it returns either 0, * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem. * The iterator's @this_arg member points to the start of the argument * associated with the current argument index that is present, which can be * found in the iterator's @this_arg_index member. This arg index corresponds * to the IEEE80211_RADIOTAP_... defines. * * Radiotap header length: * You can find the CPU-endian total radiotap header length in * iterator->max_length after executing ieee80211_radiotap_iterator_init() * successfully. * * Alignment Gotcha: * You must take care when dereferencing iterator.this_arg * for multibyte types... the pointer is not aligned. Use * get_unaligned((type *)iterator.this_arg) to dereference * iterator.this_arg for type "type" safely on all arches. * * Example code: parse.c */ int ieee80211_radiotap_iterator_init( struct ieee80211_radiotap_iterator *iterator, struct ieee80211_radiotap_header *radiotap_header, int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns) { /* must at least have the radiotap header */ if (max_length < (int)sizeof(struct ieee80211_radiotap_header)) return -EINVAL; /* Linux only supports version 0 radiotap format */ if (radiotap_header->it_version) return -EINVAL; /* sanity check for allowed length and radiotap length field */ if (max_length < get_unaligned_le16(&radiotap_header->it_len)) return -EINVAL; iterator->_rtheader = radiotap_header; iterator->_max_length = get_unaligned_le16(&radiotap_header->it_len); iterator->_arg_index = 0; iterator->_bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present); iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header); iterator->_reset_on_ext = 0; iterator->_next_bitmap = &radiotap_header->it_present; iterator->_next_bitmap++; iterator->_vns = vns; iterator->current_namespace = &radiotap_ns; iterator->is_radiotap_ns = 1; #ifdef RADIOTAP_SUPPORT_OVERRIDES iterator->n_overrides = 0; iterator->overrides = NULL; #endif /* find payload start allowing for extended bitmap(s) */ if (iterator->_bitmap_shifter & (1<_arg - (unsigned long)iterator->_rtheader + sizeof(uint32_t) > (unsigned long)iterator->_max_length) return -EINVAL; while (get_unaligned_le32(iterator->_arg) & (1 << IEEE80211_RADIOTAP_EXT)) { iterator->_arg += sizeof(uint32_t); /* * check for insanity where the present bitmaps * keep claiming to extend up to or even beyond the * stated radiotap header length */ if ((unsigned long)iterator->_arg - (unsigned long)iterator->_rtheader + sizeof(uint32_t) > (unsigned long)iterator->_max_length) return -EINVAL; } iterator->_arg += sizeof(uint32_t); /* * no need to check again for blowing past stated radiotap * header length, because ieee80211_radiotap_iterator_next * checks it before it is dereferenced */ } iterator->this_arg = iterator->_arg; /* we are all initialized happily */ return 0; } static void find_ns(struct ieee80211_radiotap_iterator *iterator, uint32_t oui, uint8_t subns) { int i; iterator->current_namespace = NULL; if (!iterator->_vns) return; for (i = 0; i < iterator->_vns->n_ns; i++) { if (iterator->_vns->ns[i].oui != oui) continue; if (iterator->_vns->ns[i].subns != subns) continue; iterator->current_namespace = &iterator->_vns->ns[i]; break; } } #ifdef RADIOTAP_SUPPORT_OVERRIDES static int find_override(struct ieee80211_radiotap_iterator *iterator, int *align, int *size) { int i; if (!iterator->overrides) return 0; for (i = 0; i < iterator->n_overrides; i++) { if (iterator->_arg_index == iterator->overrides[i].field) { *align = iterator->overrides[i].align; *size = iterator->overrides[i].size; if (!*align) /* erroneous override */ return 0; return 1; } } return 0; } #endif /** * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg * @iterator: radiotap_iterator to move to next arg (if any) * * Returns: 0 if there is an argument to handle, * -ENOENT if there are no more args or -EINVAL * if there is something else wrong. * * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*) * in @this_arg_index and sets @this_arg to point to the * payload for the field. It takes care of alignment handling and extended * present fields. @this_arg can be changed by the caller (eg, * incremented to move inside a compound argument like * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in * little-endian format whatever the endianess of your CPU. * * Alignment Gotcha: * You must take care when dereferencing iterator.this_arg * for multibyte types... the pointer is not aligned. Use * get_unaligned((type *)iterator.this_arg) to dereference * iterator.this_arg for type "type" safely on all arches. */ int ieee80211_radiotap_iterator_next( struct ieee80211_radiotap_iterator *iterator) { while (1) { int hit = 0; int pad, align, size, subns; uint32_t oui; /* if no more EXT bits, that's it */ if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT && !(iterator->_bitmap_shifter & 1)) return -ENOENT; if (!(iterator->_bitmap_shifter & 1)) goto next_entry; /* arg not present */ /* get alignment/size of data */ switch (iterator->_arg_index % 32) { case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: case IEEE80211_RADIOTAP_EXT: align = 1; size = 0; break; case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: align = 2; size = 6; break; default: #ifdef RADIOTAP_SUPPORT_OVERRIDES if (find_override(iterator, &align, &size)) { /* all set */ } else #endif if (!iterator->current_namespace || iterator->_arg_index >= iterator->current_namespace->n_bits) { if (iterator->current_namespace == &radiotap_ns) return -ENOENT; align = 0; } else { align = iterator->current_namespace->align_size[iterator->_arg_index].align; size = iterator->current_namespace->align_size[iterator->_arg_index].size; } if (!align) { /* skip all subsequent data */ iterator->_arg = iterator->_next_ns_data; /* give up on this namespace */ iterator->current_namespace = NULL; goto next_entry; } break; } /* * arg is present, account for alignment padding * * Note that these alignments are relative to the start * of the radiotap header. There is no guarantee * that the radiotap header itself is aligned on any * kind of boundary. * * The above is why get_unaligned() is used to dereference * multibyte elements from the radiotap area. */ pad = ((unsigned long)iterator->_arg - (unsigned long)iterator->_rtheader) & (align - 1); if (pad) iterator->_arg += align - pad; if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) { int vnslen; if ((unsigned long)iterator->_arg + size - (unsigned long)iterator->_rtheader > (unsigned long)iterator->_max_length) return -EINVAL; oui = (*iterator->_arg << 16) | (*(iterator->_arg + 1) << 8) | *(iterator->_arg + 2); subns = *(iterator->_arg + 3); find_ns(iterator, oui, subns); vnslen = get_unaligned_le16(iterator->_arg + 4); iterator->_next_ns_data = iterator->_arg + size + vnslen; if (!iterator->current_namespace) size += vnslen; } /* * this is what we will return to user, but we need to * move on first so next call has something fresh to test */ iterator->this_arg_index = iterator->_arg_index; iterator->this_arg = iterator->_arg; iterator->this_arg_size = size; /* internally move on the size of this arg */ iterator->_arg += size; /* * check for insanity where we are given a bitmap that * claims to have more arg content than the length of the * radiotap section. We will normally end up equalling this * max_length on the last arg, never exceeding it. */ if ((unsigned long)iterator->_arg - (unsigned long)iterator->_rtheader > (unsigned long)iterator->_max_length) return -EINVAL; /* these special ones are valid in each bitmap word */ switch (iterator->_arg_index % 32) { case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: iterator->_reset_on_ext = 1; iterator->is_radiotap_ns = 0; /* * If parser didn't register this vendor * namespace with us, allow it to show it * as 'raw. Do do that, set argument index * to vendor namespace. */ iterator->this_arg_index = IEEE80211_RADIOTAP_VENDOR_NAMESPACE; if (!iterator->current_namespace) hit = 1; goto next_entry; case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: iterator->_reset_on_ext = 1; iterator->current_namespace = &radiotap_ns; iterator->is_radiotap_ns = 1; goto next_entry; case IEEE80211_RADIOTAP_EXT: /* * bit 31 was set, there is more * -- move to next u32 bitmap */ iterator->_bitmap_shifter = get_unaligned_le32(iterator->_next_bitmap); iterator->_next_bitmap++; if (iterator->_reset_on_ext) iterator->_arg_index = 0; else iterator->_arg_index++; iterator->_reset_on_ext = 0; break; default: /* we've got a hit! */ hit = 1; next_entry: iterator->_bitmap_shifter >>= 1; iterator->_arg_index++; } /* if we found a valid arg earlier, return it now */ if (hit) return 0; } } horst-4.2/radiotap/radiotap.h000066400000000000000000000251531241274412600163060ustar00rootroot00000000000000/*- * 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. */ /* * Modifications to fit into the linux IEEE 802.11 stack, * Mike Kershaw (dragorn@kismetwireless.net) */ #ifndef IEEE80211RADIOTAP_H #define IEEE80211RADIOTAP_H #include /* Base version of the radiotap packet header data */ #define PKTHDR_RADIOTAP_VERSION 0 /* 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 describe 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. */ /* The radio capture header precedes the 802.11 header. * All data in the header is little endian on all platforms. */ struct ieee80211_radiotap_header { uint8_t it_version; /* Version 0. Only increases * for drastic changes, * introduction of compatible * new fields does not count. */ uint8_t it_pad; uint16_t it_len; /* length of the whole * header in bytes, including * it_version, it_pad, * it_len, and data fields. */ uint32_t 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. */ }; /* Name Data type Units * ---- --------- ----- * * IEEE80211_RADIOTAP_TSFT __le64 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 uint16_t MHz, bitmap * * Tx/Rx frequency in MHz, followed by flags (see below). * * IEEE80211_RADIOTAP_FHSS uint16_t see below * * For frequency-hopping radios, the hop set (first byte) * and pattern (second byte). * * IEEE80211_RADIOTAP_RATE u8 500kb/s * * Tx/Rx data rate * * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from * one milliwatt (dBm) * * RF signal power at the antenna, decibel difference from * one milliwatt. * * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from * one milliwatt (dBm) * * RF noise power at the antenna, decibel difference from one * milliwatt. * * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB) * * RF signal power at the antenna, decibel difference from an * arbitrary, fixed reference. * * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB) * * RF noise power at the antenna, decibel difference from an * arbitrary, fixed reference point. * * IEEE80211_RADIOTAP_LOCK_QUALITY uint16_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 uint16_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 uint16_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 s8 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 u8 bitmap * * Properties of transmitted and received frames. See flags * defined below. * * IEEE80211_RADIOTAP_ANTENNA u8 antenna index * * Unitless indication of the Rx/Tx antenna for this packet. * The first antenna is antenna 0. * * IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap * * Properties of received frames. See flags defined below. * * IEEE80211_RADIOTAP_TX_FLAGS uint16_t bitmap * * Properties of transmitted frames. See flags defined below. * * IEEE80211_RADIOTAP_RTS_RETRIES u8 data * * Number of rts retries a transmitted frame used. * * IEEE80211_RADIOTAP_DATA_RETRIES u8 data * * Number of unicast retries a transmitted frame used. * * IEEE80211_RADIOTAP_MCS u8, u8, u8 unitless * * Contains a bitmap of known fields/flags, the flags, and * the MCS index. * * IEEE80211_RADIOTAP_AMPDU_STATUS u32, u16, u8, u8 unitlesss * * Contains the AMPDU information for the subframe. */ 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_MCS = 19, IEEE80211_RADIOTAP_AMPDU_STATUS = 20, /* valid in every it_present bitmap, even vendor namespaces */ IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29, IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30, IEEE80211_RADIOTAP_EXT = 31 }; /* 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) */ /* 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 /* frame failed FCS check */ /* For IEEE80211_RADIOTAP_RX_FLAGS */ #define IEEE80211_RADIOTAP_F_RX_BADPLCP 0x0002 /* bad PLCP */ /* 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 */ /* For IEEE80211_RADIOTAP_AMPDU_STATUS */ #define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN 0x0001 #define IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN 0x0002 #define IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN 0x0004 #define IEEE80211_RADIOTAP_AMPDU_IS_LAST 0x0008 #define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR 0x0010 #define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN 0x0020 /* For IEEE80211_RADIOTAP_MCS */ #define IEEE80211_RADIOTAP_MCS_HAVE_BW 0x01 #define IEEE80211_RADIOTAP_MCS_HAVE_MCS 0x02 #define IEEE80211_RADIOTAP_MCS_HAVE_GI 0x04 #define IEEE80211_RADIOTAP_MCS_HAVE_FMT 0x08 #define IEEE80211_RADIOTAP_MCS_HAVE_FEC 0x10 #define IEEE80211_RADIOTAP_MCS_HAVE_STBC 0x20 #define IEEE80211_RADIOTAP_MCS_HAVE_NESS 0x40 #define IEEE80211_RADIOTAP_MCS_NESS_BIT1 0x80 #define IEEE80211_RADIOTAP_MCS_BW_MASK 0x03 #define IEEE80211_RADIOTAP_MCS_BW_20 0 #define IEEE80211_RADIOTAP_MCS_BW_40 1 #define IEEE80211_RADIOTAP_MCS_BW_20L 2 #define IEEE80211_RADIOTAP_MCS_BW_20U 3 #define IEEE80211_RADIOTAP_MCS_SGI 0x04 #define IEEE80211_RADIOTAP_MCS_FMT_GF 0x08 #define IEEE80211_RADIOTAP_MCS_FEC_LDPC 0x10 #define IEEE80211_RADIOTAP_MCS_STBC_MASK 0x60 #define IEEE80211_RADIOTAP_MCS_STBC_SHIFT 5 #define IEEE80211_RADIOTAP_MCS_STBC_1 1 #define IEEE80211_RADIOTAP_MCS_STBC_2 2 #define IEEE80211_RADIOTAP_MCS_STBC_3 3 #define IEEE80211_RADIOTAP_MCS_NESS_BIT0 0x80 #endif /* IEEE80211_RADIOTAP_H */ horst-4.2/radiotap/radiotap_iter.h000066400000000000000000000055641241274412600173350ustar00rootroot00000000000000#ifndef __RADIOTAP_ITER_H #define __RADIOTAP_ITER_H #include #include "radiotap.h" /* Radiotap header iteration * implemented in radiotap.c */ struct radiotap_override { uint8_t field; uint8_t align:4, size:4; }; struct radiotap_align_size { uint8_t align:4, size:4; }; struct ieee80211_radiotap_namespace { const struct radiotap_align_size *align_size; int n_bits; uint32_t oui; uint8_t subns; }; struct ieee80211_radiotap_vendor_namespaces { const struct ieee80211_radiotap_namespace *ns; int n_ns; }; /** * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args * @this_arg_index: index of current arg, valid after each successful call * to ieee80211_radiotap_iterator_next() * @this_arg: pointer to current radiotap arg; it is valid after each * call to ieee80211_radiotap_iterator_next() but also after * ieee80211_radiotap_iterator_init() where it will point to * the beginning of the actual data portion * @this_arg_size: length of the current arg, for convenience * @current_namespace: pointer to the current namespace definition * (or internally %NULL if the current namespace is unknown) * @is_radiotap_ns: indicates whether the current namespace is the default * radiotap namespace or not * * @overrides: override standard radiotap fields * @n_overrides: number of overrides * * @_rtheader: pointer to the radiotap header we are walking through * @_max_length: length of radiotap header in cpu byte ordering * @_arg_index: next argument index * @_arg: next argument pointer * @_next_bitmap: internal pointer to next present u32 * @_bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present * @_vns: vendor namespace definitions * @_next_ns_data: beginning of the next namespace's data * @_reset_on_ext: internal; reset the arg index to 0 when going to the * next bitmap word * * Describes the radiotap parser state. Fields prefixed with an underscore * must not be used by users of the parser, only by the parser internally. */ struct ieee80211_radiotap_iterator { struct ieee80211_radiotap_header *_rtheader; const struct ieee80211_radiotap_vendor_namespaces *_vns; const struct ieee80211_radiotap_namespace *current_namespace; unsigned char *_arg, *_next_ns_data; uint32_t *_next_bitmap; unsigned char *this_arg; #ifdef RADIOTAP_SUPPORT_OVERRIDES const struct radiotap_override *overrides; int n_overrides; #endif int this_arg_index; int this_arg_size; int is_radiotap_ns; int _max_length; int _arg_index; uint32_t _bitmap_shifter; int _reset_on_ext; }; extern int ieee80211_radiotap_iterator_init( struct ieee80211_radiotap_iterator *iterator, struct ieee80211_radiotap_header *radiotap_header, int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns); extern int ieee80211_radiotap_iterator_next( struct ieee80211_radiotap_iterator *iterator); #endif /* __RADIOTAP_ITER_H */ horst-4.2/util.c000066400000000000000000000060371241274412600136500ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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" 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; } #if DO_DEBUG void dump_packet(const unsigned char* buf, int len) { int i; for (i = 0; i < len; i++) { if ((i % 2) == 0) { printf(" "); } if ((i % 16) == 0) { printf("\n"); } printf("%02x", buf[i]); } printf("\n"); } #else void dump_packet(__attribute__((unused)) const unsigned char* buf, __attribute__((unused)) int len) { } #endif 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++; } } 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-4.2/util.h000066400000000000000000000062071241274412600136540ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 #ifdef _ALLBSD_SOURCE #include #elif __linux__ #include #endif #if defined(__APPLE__) #include #define le64toh(x) OSSwapLittleToHostInt64(x) #define le32toh(x) OSSwapLittleToHostInt32(x) #define le16toh(x) OSSwapLittleToHostInt16(x) #define htole64(x) OSSwapHostToLittleInt64(x) #define htole32(x) OSSwapHostToLittleInt32(x) #define htole16(x) OSSwapHostToLittleInt16(x) #else #include #endif #if BYTE_ORDER == LITTLE_ENDIAN #if !defined(le64toh) #define le64toh(x) (x) #endif #if !defined(le32toh) #define le32toh(x) (x) #endif #if !defined(le16toh) #define le16toh(x) (x) #endif #if !defined(htole64) #define htole64(x) (x) #endif #if !defined(htole32) #define htole32(x) (x) #endif #if !defined(htole16) #define htole16(x) (x) #endif #else #if !defined(le64toh) #define le64toh(x) bswap_64(x) #endif #if !defined(le32toh) #define le32toh(x) bswap_32(x) #endif #if !defined(le16toh) #define le16toh(x) bswap_16(x) #endif #if !defined(htole64) #define htole64(x) bswap_64(x) #endif #if !defined(htole32) #define htole32(x) bswap_32(x) #endif #if !defined(htole16) #define htole16(x) bswap_16(x) #endif #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); } 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-4.2/wext.c000066400000000000000000000061671241274412600136660ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 "wext.h" #include "main.h" #include "util.h" #if defined(__APPLE__) int wext_set_freq(__attribute__((unused)) int fd, __attribute__((unused)) const char* devname, __attribute__((unused)) int freq) { return 0; } int wext_get_freq(__attribute__((unused)) int fd, __attribute__((unused)) const char* devname) { return 0; } int wext_get_channels(__attribute__((unused)) int fd, __attribute__((unused)) const char* devname, __attribute__((unused)) struct chan_freq channels[MAX_CHANNELS]) { return 0; } #else #include #include #include 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) 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; } #endif horst-4.2/wext.h000066400000000000000000000021241241274412600136600ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 "channel.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_ horst-4.2/wlan80211.h000066400000000000000000000127701241274412600142360ustar00rootroot00000000000000#ifndef _WLAN_HEADER_H_ #define _WLAN_HEADER_H_ #include struct wlan_frame { u_int16_t fc; u_int16_t duration; u_int8_t addr1[6]; u_int8_t addr2[6]; u_int8_t addr3[6]; u_int16_t seq; union { u_int16_t qos; u_int8_t addr4[6]; struct { u_int16_t qos; u_int32_t ht; } __attribute__ ((packed)) ht; struct { u_int8_t addr4[6]; u_int16_t qos; u_int32_t ht; } __attribute__ ((packed)) addr4_qos_ht; } u; } __attribute__ ((packed)); #define WLAN_FRAME_FC_VERSION_MASK 0x0003 #define WLAN_FRAME_FC_TYPE_MASK 0x000C #define WLAN_FRAME_FC_STYPE_MASK 0x00F0 #define WLAN_FRAME_FC_STYPE_QOS 0x0080 #define WLAN_FRAME_FC_TO_DS 0x0100 #define WLAN_FRAME_FC_FROM_DS 0x0200 #define WLAN_FRAME_FC_MORE_FRAG 0x0400 #define WLAN_FRAME_FC_RETRY 0x0800 #define WLAN_FRAME_FC_POWER_MGMT 0x1000 #define WLAN_FRAME_FC_MORE_DATA 0x2000 #define WLAN_FRAME_FC_PROTECTED 0x4000 #define WLAN_FRAME_FC_ORDER 0x8000 #define WLAN_FRAME_FC_MASK (WLAN_FRAME_FC_TYPE_MASK | WLAN_FRAME_FC_STYPE_MASK) /* internal use only */ #define _WLAN_FRAME_FC(_type, _stype) (((_type) << 2) | ((_stype) << 4)) #define _FC_TYPE_MGMT 0x0 #define _FC_TYPE_CTRL 0x1 #define _FC_TYPE_DATA 0x2 /* main types */ #define WLAN_FRAME_TYPE_MGMT _WLAN_FRAME_FC(_FC_TYPE_MGMT, 0x0) #define WLAN_FRAME_TYPE_CTRL _WLAN_FRAME_FC(_FC_TYPE_CTRL, 0x0) #define WLAN_FRAME_TYPE_DATA _WLAN_FRAME_FC(_FC_TYPE_DATA, 0x0) #define WLAN_FRAME_IS_MGMT(_fc) (((_fc) & WLAN_FRAME_FC_TYPE_MASK) == WLAN_FRAME_TYPE_MGMT) #define WLAN_FRAME_IS_CTRL(_fc) (((_fc) & WLAN_FRAME_FC_TYPE_MASK) == WLAN_FRAME_TYPE_CTRL) #define WLAN_FRAME_IS_DATA(_fc) (((_fc) & WLAN_FRAME_FC_TYPE_MASK) == WLAN_FRAME_TYPE_DATA) #define WLAN_FRAME_IS_QOS(_fc) (((_fc) & WLAN_FRAME_FC_STYPE_MASK) == WLAN_FRAME_FC_STYPE_QOS) /*** management ***/ #define WLAN_FRAME_ASSOC_REQ _WLAN_FRAME_FC(_FC_TYPE_MGMT, 0x0) #define WLAN_FRAME_ASSOC_RESP _WLAN_FRAME_FC(_FC_TYPE_MGMT, 0x1) #define WLAN_FRAME_REASSOC_REQ _WLAN_FRAME_FC(_FC_TYPE_MGMT, 0x2) #define WLAN_FRAME_REASSOC_RESP _WLAN_FRAME_FC(_FC_TYPE_MGMT, 0x3) #define WLAN_FRAME_PROBE_REQ _WLAN_FRAME_FC(_FC_TYPE_MGMT, 0x4) #define WLAN_FRAME_PROBE_RESP _WLAN_FRAME_FC(_FC_TYPE_MGMT, 0x5) #define WLAN_FRAME_TIMING _WLAN_FRAME_FC(_FC_TYPE_MGMT, 0x6) /* (reserved) 0x7 */ #define WLAN_FRAME_BEACON _WLAN_FRAME_FC(_FC_TYPE_MGMT, 0x8) #define WLAN_FRAME_ATIM _WLAN_FRAME_FC(_FC_TYPE_MGMT, 0x9) #define WLAN_FRAME_DISASSOC _WLAN_FRAME_FC(_FC_TYPE_MGMT, 0xa) #define WLAN_FRAME_AUTH _WLAN_FRAME_FC(_FC_TYPE_MGMT, 0xb) #define WLAN_FRAME_DEAUTH _WLAN_FRAME_FC(_FC_TYPE_MGMT, 0xc) #define WLAN_FRAME_ACTION _WLAN_FRAME_FC(_FC_TYPE_MGMT, 0xd) #define WLAN_FRAME_ACTION_NOACK _WLAN_FRAME_FC(_FC_TYPE_MGMT, 0xe) /* (reserved) 0xf */ /*** control ***/ /* (reserved) 0-6 */ #define WLAN_FRAME_CTRL_WRAP _WLAN_FRAME_FC(_FC_TYPE_CTRL, 0x7) #define WLAN_FRAME_BLKACK_REQ _WLAN_FRAME_FC(_FC_TYPE_CTRL, 0x8) #define WLAN_FRAME_BLKACK _WLAN_FRAME_FC(_FC_TYPE_CTRL, 0x9) #define WLAN_FRAME_PSPOLL _WLAN_FRAME_FC(_FC_TYPE_CTRL, 0xa) #define WLAN_FRAME_RTS _WLAN_FRAME_FC(_FC_TYPE_CTRL, 0xb) #define WLAN_FRAME_CTS _WLAN_FRAME_FC(_FC_TYPE_CTRL, 0xc) #define WLAN_FRAME_ACK _WLAN_FRAME_FC(_FC_TYPE_CTRL, 0xd) #define WLAN_FRAME_CF_END _WLAN_FRAME_FC(_FC_TYPE_CTRL, 0xe) #define WLAN_FRAME_CF_END_ACK _WLAN_FRAME_FC(_FC_TYPE_CTRL, 0xf) /*** data ***/ #define WLAN_FRAME_DATA _WLAN_FRAME_FC(_FC_TYPE_DATA, 0x0) #define WLAN_FRAME_DATA_CF_ACK _WLAN_FRAME_FC(_FC_TYPE_DATA, 0x1) #define WLAN_FRAME_DATA_CF_POLL _WLAN_FRAME_FC(_FC_TYPE_DATA, 0x2) #define WLAN_FRAME_DATA_CF_ACKPOLL _WLAN_FRAME_FC(_FC_TYPE_DATA, 0x3) #define WLAN_FRAME_NULL _WLAN_FRAME_FC(_FC_TYPE_DATA, 0x4) #define WLAN_FRAME_CF_ACK _WLAN_FRAME_FC(_FC_TYPE_DATA, 0x5) #define WLAN_FRAME_CF_POLL _WLAN_FRAME_FC(_FC_TYPE_DATA, 0x6) #define WLAN_FRAME_CF_ACKPOLL _WLAN_FRAME_FC(_FC_TYPE_DATA, 0x7) #define WLAN_FRAME_QDATA _WLAN_FRAME_FC(_FC_TYPE_DATA, 0x8) #define WLAN_FRAME_QDATA_CF_ACK _WLAN_FRAME_FC(_FC_TYPE_DATA, 0x9) #define WLAN_FRAME_QDATA_CF_POLL _WLAN_FRAME_FC(_FC_TYPE_DATA, 0xa) #define WLAN_FRAME_QDATA_CF_ACKPOLL _WLAN_FRAME_FC(_FC_TYPE_DATA, 0xb) #define WLAN_FRAME_QOS_NULL _WLAN_FRAME_FC(_FC_TYPE_DATA, 0xc) /* (reserved) 0xd */ #define WLAN_FRAME_QOS_CF_POLL _WLAN_FRAME_FC(_FC_TYPE_DATA, 0xe) #define WLAN_FRAME_QOS_CF_ACKPOLL _WLAN_FRAME_FC(_FC_TYPE_DATA, 0xf) #define WLAN_FRAME_QOS_TID_MASK 0x7 #define WLAN_FRAME_QOS_AMSDU_PRESENT 0x80 /*** individual frame formats ***/ /* beacon + probe response */ struct wlan_frame_beacon { u_int64_t tsf; u_int16_t bintval; u_int16_t capab; unsigned char ie[0]; } __attribute__ ((packed)); /*** capabilities ***/ #define WLAN_CAPAB_ESS 0x0001 #define WLAN_CAPAB_IBSS 0x0002 #define WLAN_CAPAB_CF_POLL 0x0004 #define WLAN_CAPAB_CF_POLL_REQ 0x0008 #define WLAN_CAPAB_PRIVACY 0x0010 #define WLAN_CAPAB_SHORT_PRE 0x0020 #define WLAN_CAPAB_PBCC 0x0040 #define WLAN_CAPAB_CHAN_AGILIY 0x0080 #define WLAN_CAPAB_SPECT_MGMT 0x0100 #define WLAN_CAPAB_QOS 0x0200 #define WLAN_CAPAB_SHORT_SLOT 0x0400 #define WLAN_CAPAB_APSD 0x0800 #define WLAN_CAPAB_RADIO_MEAS 0x1000 #define WLAN_CAPAB_OFDM 0x2000 #define WLAN_CAPAB_DEL_BLKACK 0x4000 #define WLAN_CAPAB_IMM_BLKACK 0x8000 /*** information elements ***/ struct information_element { u_int8_t id; u_int8_t len; unsigned char var[0]; }; /* only the information element IDs we are interested in */ #define WLAN_IE_ID_SSID 0 #define WLAN_IE_ID_DSSS_PARAM 3 #define WLAN_IE_ID_RSN 48 #define WLAN_IE_ID_VENDOR 221 #define WLAN_MAX_SSID_LEN 34 #endif horst-4.2/wlan_util.c000066400000000000000000000172431241274412600146720ustar00rootroot00000000000000#include "main.h" #include "util.h" #include "wlan80211.h" #include "wlan_util.h" /* lists of packet names */ static struct pkt_name mgmt_names[] = { { 'a', "ASOCRQ", WLAN_FRAME_ASSOC_REQ, "Association request" }, { 'A', "ASOCRP", WLAN_FRAME_ASSOC_RESP, "Association response" }, { 'a', "REASRQ", WLAN_FRAME_REASSOC_REQ, "Reassociation request" }, { 'A', "REASRP", WLAN_FRAME_REASSOC_RESP, "Reassociation response" }, { 'p', "PROBRQ", WLAN_FRAME_PROBE_REQ, "Probe request" }, { 'P', "PROBRP", WLAN_FRAME_PROBE_RESP, "Probe response" }, { 'T', "TIMING", WLAN_FRAME_TIMING, "Timing Advertisement" }, { '-', "-RESV-", 0x0070, "RESERVED" }, { 'B', "BEACON", WLAN_FRAME_BEACON, "Beacon" }, { 't', "ATIM", WLAN_FRAME_ATIM, "ATIM" }, { 'D', "DISASC", WLAN_FRAME_DISASSOC, "Disassociation" }, { 'u', "AUTH", WLAN_FRAME_AUTH, "Authentication" }, { 'U', "DEAUTH", WLAN_FRAME_DEAUTH, "Deauthentication" }, { 'C', "ACTION", WLAN_FRAME_ACTION, "Action" }, { 'c', "ACTNOA", WLAN_FRAME_ACTION_NOACK, "Action No Ack" }, }; static struct pkt_name ctrl_names[] = { { 'w', "CTWRAP", WLAN_FRAME_CTRL_WRAP, "Control Wrapper" }, { 'b', "BACKRQ", WLAN_FRAME_BLKACK_REQ, "Block Ack Request" }, { 'B', "BACK", WLAN_FRAME_BLKACK, "Block Ack" }, { 's', "PSPOLL", WLAN_FRAME_PSPOLL, "PS-Poll" }, { 'R', "RTS", WLAN_FRAME_RTS, "RTS" }, { 'C', "CTS", WLAN_FRAME_CTS, "CTS" }, { 'K', "ACK", WLAN_FRAME_ACK, "ACK" }, { 'f', "CFEND", WLAN_FRAME_CF_END, "CF-End" }, { 'f', "CFENDK", WLAN_FRAME_CF_END_ACK, "CF-End + CF-Ack" }, }; static struct pkt_name data_names[] = { { 'D', "DATA", WLAN_FRAME_DATA, "Data" }, { 'F', "DCFACK", WLAN_FRAME_DATA_CF_ACK, "Data + CF-Ack" }, { 'F', "DCFPLL", WLAN_FRAME_DATA_CF_POLL, "Data + CF-Poll" }, { 'F', "DCFKPL", WLAN_FRAME_DATA_CF_ACKPOLL, "Data + CF-Ack + CF-Poll" }, { 'n', "NULL", WLAN_FRAME_NULL, "Null (no data)" }, { 'f', "CFACK", WLAN_FRAME_CF_ACK, "CF-Ack (no data)" }, { 'f', "CFPOLL", WLAN_FRAME_CF_POLL, "CF-Poll (no data)" }, { 'f', "CFCKPL", WLAN_FRAME_CF_ACKPOLL, "CF-Ack + CF-Poll (no data)" }, { 'Q', "QDATA", WLAN_FRAME_QDATA, "QoS Data" }, { 'F', "QDCFCK", WLAN_FRAME_QDATA_CF_ACK, "QoS Data + CF-Ack" }, { 'F', "QDCFPL", WLAN_FRAME_QDATA_CF_POLL, "QoS Data + CF-Poll" }, { 'F', "QDCFKP", WLAN_FRAME_QDATA_CF_ACKPOLL, "QoS Data + CF-Ack + CF-Poll" }, { 'N', "QDNULL", WLAN_FRAME_QOS_NULL, "QoS Null (no data)" }, { '-', "-RESV-", 0x00D0, "RESERVED" }, { 'f', "QCFPLL", WLAN_FRAME_QOS_CF_POLL, "QoS CF-Poll (no data)" }, { 'f', "QCFKPL", WLAN_FRAME_QOS_CF_ACKPOLL, "QoS CF-Ack + CF-Poll (no data)" }, }; static struct pkt_name unknow = { '?', "UNKNOW", 0 , "Unknown" }; static struct pkt_name badfcs = { '*', "BADFCS", 0 , "Bad FCS" }; #define DATA_NAME_INDEX(_i) (((_i) & WLAN_FRAME_FC_STYPE_MASK)>>4) #define MGMT_NAME_INDEX(_i) (((_i) & WLAN_FRAME_FC_STYPE_MASK)>>4) #define CTRL_NAME_INDEX(_i) ((((_i) & WLAN_FRAME_FC_STYPE_MASK)>>4)-7) struct pkt_name get_packet_struct(u_int16_t type) { u_int16_t index; if (type == 1) /* special case for bad FCS */ return badfcs; if (WLAN_FRAME_IS_MGMT(type)) { index = MGMT_NAME_INDEX(type); if (index < sizeof(mgmt_names)/sizeof(struct pkt_name)) { if (mgmt_names[index].c) return mgmt_names[index]; } } else if (WLAN_FRAME_IS_CTRL(type)) { index = CTRL_NAME_INDEX(type); if (index < sizeof(ctrl_names)/sizeof(struct pkt_name)) { if (ctrl_names[index].c) return ctrl_names[index]; } } else if (WLAN_FRAME_IS_DATA(type)) { index = DATA_NAME_INDEX(type); if (index < sizeof(data_names)/sizeof(struct pkt_name)) { if (data_names[index].c) return data_names[index]; } } return unknow; } char get_packet_type_char(u_int16_t type) { return get_packet_struct(type).c; } const char* get_packet_type_name(u_int16_t type) { return get_packet_struct(type).name; } /* rate in 100kbps */ int rate_to_index(int rate) { switch (rate) { case 540: return 12; case 480: return 11; case 360: return 10; case 240: return 9; case 180: return 8; case 120: return 7; case 110: return 6; case 90: return 5; case 60: return 4; case 55: return 3; case 20: return 2; case 10: return 1; default: return 0; } } /* return rate in 100kbps */ int rate_index_to_rate(int idx) { switch (idx) { case 12: return 540; case 11: return 480; case 10: return 360; case 9: return 240; case 8: return 180; case 7: return 120; case 6: return 110; case 5: return 90; case 4: return 60; case 3: return 55; case 2: return 20; case 1: return 10; default: return 0; } } /* return rate in 100kbps */ int mcs_index_to_rate(int mcs, int ht20, int lgi) { /* MCS Index, http://en.wikipedia.org/wiki/IEEE_802.11n-2009#Data_rates */ switch (mcs) { case 0: return ht20 ? (lgi ? 65 : 72) : (lgi ? 135 : 150); case 1: return ht20 ? (lgi ? 130 : 144) : (lgi ? 270 : 300); case 2: return ht20 ? (lgi ? 195 : 217) : (lgi ? 405 : 450); case 3: return ht20 ? (lgi ? 260 : 289) : (lgi ? 540 : 600); case 4: return ht20 ? (lgi ? 390 : 433) : (lgi ? 810 : 900); case 5: return ht20 ? (lgi ? 520 : 578) : (lgi ? 1080 : 1200); case 6: return ht20 ? (lgi ? 585 : 650) : (lgi ? 1215 : 1350); case 7: return ht20 ? (lgi ? 650 : 722) : (lgi ? 1350 : 1500); case 8: return ht20 ? (lgi ? 130 : 144) : (lgi ? 270 : 300); case 9: return ht20 ? (lgi ? 260 : 289) : (lgi ? 540 : 600); case 10: return ht20 ? (lgi ? 390 : 433) : (lgi ? 810 : 900); case 11: return ht20 ? (lgi ? 520 : 578) : (lgi ? 1080 : 1200); case 12: return ht20 ? (lgi ? 780 : 867) : (lgi ? 1620 : 1800); case 13: return ht20 ? (lgi ? 1040 : 1156) : (lgi ? 2160 : 2400); case 14: return ht20 ? (lgi ? 1170 : 1300) : (lgi ? 2430 : 2700); case 15: return ht20 ? (lgi ? 1300 : 1444) : (lgi ? 2700 : 3000); case 16: return ht20 ? (lgi ? 195 : 217) : (lgi ? 405 : 450); case 17: return ht20 ? (lgi ? 39 : 433) : (lgi ? 810 : 900); case 18: return ht20 ? (lgi ? 585 : 650) : (lgi ? 1215 : 1350); case 19: return ht20 ? (lgi ? 78 : 867) : (lgi ? 1620 : 1800); case 20: return ht20 ? (lgi ? 1170 : 1300) : (lgi ? 2430 : 2700); case 21: return ht20 ? (lgi ? 1560 : 1733) : (lgi ? 3240 : 3600); case 22: return ht20 ? (lgi ? 1755 : 1950) : (lgi ? 3645 : 4050); case 23: return ht20 ? (lgi ? 1950 : 2167) : (lgi ? 4050 : 4500); case 24: return ht20 ? (lgi ? 260 : 288) : (lgi ? 540 : 600); case 25: return ht20 ? (lgi ? 520 : 576) : (lgi ? 1080 : 1200); case 26: return ht20 ? (lgi ? 780 : 868) : (lgi ? 1620 : 1800); case 27: return ht20 ? (lgi ? 1040 : 1156) : (lgi ? 2160 : 2400); case 28: return ht20 ? (lgi ? 1560 : 1732) : (lgi ? 3240 : 3600); case 29: return ht20 ? (lgi ? 2080 : 2312) : (lgi ? 4320 : 4800); case 30: return ht20 ? (lgi ? 2340 : 2600) : (lgi ? 4860 : 5400); case 31: return ht20 ? (lgi ? 2600 : 2888) : (lgi ? 5400 : 6000); } return 0; } void wlan_parse_information_elements(unsigned char *buf, int len, struct packet_info *p) { while (len > 2) { struct information_element* ie = (struct information_element*)buf; //DEBUG("------ IE %d len %d t len %d\n", ie->id, ie->len, len); switch (ie->id) { case WLAN_IE_ID_SSID: if (ie->len < WLAN_MAX_SSID_LEN-1) { memcpy(p->wlan_essid, ie->var, ie->len); p->wlan_essid[ie->len] = '\0'; } else { memcpy(p->wlan_essid, ie->var, WLAN_MAX_SSID_LEN-1); p->wlan_essid[WLAN_MAX_SSID_LEN-1] = '\0'; } break; case WLAN_IE_ID_DSSS_PARAM: p->wlan_channel = *ie->var; break; case WLAN_IE_ID_RSN: p->wlan_rsn = 1; break; case WLAN_IE_ID_VENDOR: if (ie->len >= 4 && ie->var[0] == 0x00 && ie->var[1] == 0x50 && ie->var[2] == 0xf2 && /* Microsoft OUI (00:50:F2) */ ie->var[3] == 1) { /* OUI Type 1 - WPA IE */ p->wlan_wpa=1; } break; } buf += (ie->len + 2); len -= (ie->len + 2); } } horst-4.2/wlan_util.h000066400000000000000000000025041241274412600146710ustar00rootroot00000000000000/* horst - Highly Optimized Radio Scanning Tool * * Copyright (C) 2005-2014 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 _WLAN_UTIL_H_ #define _WLAN_UTIL_H_ struct pkt_name { char c; const char* name; u_int16_t fc; const char* desc; }; struct pkt_name get_packet_struct(u_int16_t type); char get_packet_type_char(u_int16_t type); const char* get_packet_type_name(u_int16_t type); int rate_to_index(int rate); int rate_index_to_rate(int idx); int mcs_index_to_rate(int mcs, int ht20, int lgi); struct packet_info; void wlan_parse_information_elements(unsigned char *buf, int len, struct packet_info *p); #endif