13
0
Fork 1

initial commit of the linux driver

for the dosch and amand dect pcmcia card.

Currently only the type II card is supported.



git-svn-id: https://dedected.org/svn/trunk@3 8d8ab74c-27aa-4a3d-9bde-523a2bc1f624
This commit is contained in:
dedected 2008-12-29 00:56:07 +00:00
parent d652a68cd9
commit 56ecf4776a
36 changed files with 5795 additions and 0 deletions

339
com-on-air_cs-linux/LICENSE Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@ -0,0 +1,46 @@
NODE:=/dev/coa
PCMCIA_SLOT:=1
-include pcmcia_slot.make
ifneq ($(KERNELRELEASE),)
obj-m := com_on_air_cs.o
com_on_air_cs-objs := com_on_air.o sc14421.o sc14421_sniffer.o sc14421_firmware.o dect.o
else
KDIR ?= /lib/modules/`uname -r`/build/
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) M=$(PWD) modules
endif
load: node
insmod ./com_on_air_cs.ko && \
pccardctl insert $(PCMCIA_SLOT)
unload:
pccardctl eject $(PCMCIA_SLOT) && \
rmmod com_on_air_cs
reload:
pccardctl eject $(PCMCIA_SLOT) && \
rmmod com_on_air_cs && \
insmod ./com_on_air_cs.ko && \
pccardctl insert $(PCMCIA_SLOT)
node: $(NODE)
$(NODE):
mknod $@ --mode 660 c 3564 0 ### 3564 == 0xDEC
# chgrp dect $(NODE)
read: node coa_read
tools/coa_read
watch: node coa_read
watch -n 0.2 ./tools/coa_read
clean:
rm -rf com_on_air_cs.ko com_on_air_cs.mod.c .com_on_air* .sc14421* .tmp* Module.symvers modules.order *.o

View File

@ -0,0 +1,37 @@
!!! for scientific and research purposes only !!!
what
~~~~
com_on_air_cs is a very basic driver for the Dosch & Amand com-on-air PCMCIA
DECT cards.
In the tools/ subdir you find userspace tools using the driver
license
~~~~~~~
GNU GENERAL PUBLIC LICENSE Version 2
see LICENSE
authors
~~~~~~~
Matthias Wenzel <dect at mazzoo dot de>
Andreas Schuler <krater at badterrorist dot com>
install
~~~~~~~
make && make -C tools # compiles the driver and userspace tools
make node # create the /dev/coa character device
running
~~~~~~~
the most featurecomplete tool for now is dect_cli. it can dump pcap
formatted captures. just run it and type help.
coa_syncsniff dumps pcap files on a given channel and RFPI
pcap2cchan dumps C-channel information from pcap files
pcapstein dumps all B-Fields found in a pcap file

View File

@ -0,0 +1,823 @@
/*
* com_on_air_cs - basic driver for the Dosch and Amand "com on air" cards
*
* 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.
*
* authors:
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/crc32.h>
#include <linux/kfifo.h>
#include <linux/poll.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ciscode.h>
#include <pcmcia/ds.h>
#include <pcmcia/cisreg.h>
#include <asm/uaccess.h>
#include "com_on_air.h"
#include "com_on_air_user.h" /* ioctls ... */
#include "sc14421.h"
#include "sc14421_sniffer.h"
MODULE_AUTHOR("Matthias Wenzel comonair<a>mazzoo.de;"
"Andreas Schuler dect<a>badterrorist.com");
MODULE_DESCRIPTION("Dosch&Amand COM-ON-AIR PCMCIA driver");
MODULE_LICENSE("GPL");
#define COA_DEVICE_NAME "com_on_air_cs"
#define COA_FIFO_SIZE 65536
struct coa_info *dev;
static int coa_open(struct inode *inode, struct file *filp)
{
if (dev->open)
return -EBUSY;
dev->open = 1;
return nonseekable_open(inode, filp);
}
/* we use some "hidden" ioctls */
#define COA_IOCTL_TEST0 0xF000
#define COA_IOCTL_TEST1 0xF001
#define COA_IOCTL_TEST2 0xF002
#define COA_IOCTL_TEST3 0xF003
#define COA_IOCTL_TEST4 0xF004
#define COA_IOCTL_TEST5 0xF005
#define COA_IOCTL_TEST6 0xF006
#define COA_IOCTL_TEST7 0xF007
int coa_ioctl(
struct inode *inode,
struct file *filp,
unsigned int cmd,
unsigned long arg)
{
unsigned long __user * argp = (unsigned long __user *) arg;
if (!dev->p_dev->dev_node)
return -EIO;
switch (cmd)
{
case COA_IOCTL_MODE:
{
uint16_t mode;
if (copy_from_user(&mode, argp, sizeof(mode)))
{
printk(COA_DEVICE_NAME
": invalid argument in ioctl()\n");
return -EINVAL;
}
switch (mode & COA_MODEMASK)
{
case COA_MODE_IDLE:
printk("com_on_air_cs: stopping DIP\n");
SC14421_stop_dip(dev->sc14421_base);
dev->operation_mode = mode;
kfifo_reset(dev->rx_fifo);
kfifo_reset(dev->tx_fifo);
break;
case COA_MODE_FP:
printk("FIXME: implement COA_MODE_FP ;)\n");
break;
case COA_MODE_PP:
printk("FIXME: implement COA_MODE_PP ;)\n");
break;
case COA_MODE_SNIFF:
kfifo_reset(dev->rx_fifo);
kfifo_reset(dev->tx_fifo);
/* activiate sniffer */
if (!dev->sniffer_config)
dev->sniffer_config =
kzalloc(sizeof(*dev->sniffer_config),
GFP_KERNEL);
if (!(dev->sniffer_config))
return -ENOMEM;
dev->sniffer_config->snifftype = mode & COA_SUBMODEMASK;
dev->sniffer_config->channel = 0;
dev->operation_mode = mode;
sniffer_init(dev);
printk(COA_DEVICE_NAME": sniffer initialized\n");
break;
case COA_MODE_JAM:
printk("FIXME: implement COA_MODE_JAM\n");
break;
default:
printk("coa: invalid ioctl() value "
"for COA_IOCTL_MODE\n");
return -EINVAL;
}
break;
}
case COA_IOCTL_RADIO:
printk("FIXME: implement COA_IOCTL_RADIO\n");
break;
case COA_IOCTL_RX:
printk("FIXME: implement COA_IOCTL_RX\n");
break;
case COA_IOCTL_TX:
printk("FIXME: implement COA_IOCTL_TX\n");
break;
case COA_IOCTL_CHAN:
{
uint32_t channel;
if (copy_from_user(&channel, argp, sizeof(channel)))
{
printk(COA_DEVICE_NAME": invalid argument "
"in ioctl()\n");
return -EINVAL;
}
if (channel > 10)
return -EINVAL;
switch (dev->operation_mode & COA_MODEMASK)
{
case COA_MODE_IDLE:
break;
case COA_MODE_FP:
/* FIXME: implement COA_MODE_FP ;) */
break;
case COA_MODE_PP:
/* FIXME: implement COA_MODE_PP ;) */
break;
case COA_MODE_SNIFF:
dev->sniffer_config->channel = channel;
break;
case COA_MODE_JAM:
printk("FIXME: implement COA_MODE_JAM\n");
break;
default:
printk("coa: invalid ioctl() value "
"for COA_IOCTL_MODE\n");
return -EINVAL;
}
sniffer_init(dev);
break;
}
case COA_IOCTL_SLOT:
printk("FIXME: implement COA_IOCTL_SLOT\n");
break;
case COA_IOCTL_RSSI:
printk("FIXME: implement COA_IOCTL_RSSI\n");
break;
case COA_IOCTL_FIRMWARE:
printk("FIXME: implement COA_IOCTL_FIRMWARE\n");
break;
case COA_IOCTL_SETRFPI:
{
uint8_t RFPI[5];
if (copy_from_user(&RFPI, argp, sizeof(RFPI)))
{
printk(COA_DEVICE_NAME": invalid argument in ioctl()\n");
return -EINVAL;
}
switch (dev->operation_mode & COA_MODEMASK)
{
case COA_MODE_IDLE:
break;
case COA_MODE_FP:
/* FIXME: implement COA_MODE_FP ;) */
break;
case COA_MODE_PP:
/* FIXME: implement COA_MODE_PP ;) */
break;
case COA_MODE_SNIFF:
memcpy(dev->sniffer_config->RFPI, RFPI, sizeof(dev->sniffer_config->RFPI));
break;
case COA_MODE_JAM:
printk("FIXME: implement COA_MODE_JAM\n");
break;
default:
printk("coa: invalid ioctl() value for COA_IOCTL_MODE\n");
return -EINVAL;
}
break;
}
case COA_IOCTL_TEST7:
case COA_IOCTL_TEST6:
case COA_IOCTL_TEST5:
case COA_IOCTL_TEST4:
case COA_IOCTL_TEST3:
case COA_IOCTL_TEST2:
{
printk("\n\ncom_on_air_cs: saw %d interrupts since loading\n\n\n",
dev->irq_count);
break;
}
case COA_IOCTL_TEST1:
{
static char teststring[] = "awake. "
"shake dreams from your head my pretty child, "
"my swet one. choose the day "
"and choose the sign of your day. "
"the day's divinity.\n";
static char * ps = teststring;
int ret;
ret = kfifo_put(dev->rx_fifo, ps, 1);
if (ret <= 0)
printk("com_on_air_cs: rx fifo full? "
"kfifo_put() = %d\n", ret);
ps++;
if (!*ps)
ps = teststring;
break;
}
case COA_IOCTL_TEST0:
{
unsigned char bank;
int a, b, i;
printk("dumping complete DIP-RAM\n");
disable_irq(dev->irq);
for (i = 0; i < 8; i++)
{
bank = (4 * i);
SC14421_switch_to_bank(dev->sc14421_base, bank);
printk("Setting Banking-Register to %.2x\n\n", bank);
for (a = 0; a < 16; a++)
{
unsigned short *sc14421_base = dev->sc14421_base;
for (b = 0; b < 16; b++)
printk("%.2x ",
(unsigned char)
SC14421_READ( a*16 + b) );
#if 0
if (SC14421_READ(511) & 0x0f)
printk("%.2x ",
(unsigned char)
(SC14421_READ(511)));
printk("\n");
#endif
}
}
enable_irq(dev->irq);
break;
}
default:
printk("coa: invalid ioctl()\n");
return -EINVAL;
}
return 0;
}
static unsigned int coa_poll(struct file *file, poll_table * wait)
{
unsigned int mask = 0;
if (!dev->p_dev->dev_node)
return -EIO;
if (kfifo_len(dev->rx_fifo))
mask |= POLLIN | POLLRDNORM;
if (COA_FIFO_SIZE - kfifo_len(dev->tx_fifo))
mask |= POLLOUT | POLLWRNORM;
return mask;
}
static ssize_t coa_read(
struct file *filp,
char __user *buf,
size_t count_want,
loff_t *ppos)
{
size_t to_copy;
size_t not_copied;
unsigned char *data;
if (!dev->p_dev->dev_node)
return -EIO;
to_copy = min(kfifo_len(dev->rx_fifo), count_want);
data = kmalloc(to_copy, GFP_KERNEL);
if (!data)
return -ENOMEM;
to_copy = kfifo_get(dev->rx_fifo, data, to_copy);
if (to_copy < 0) {
kfree(data);
return -EIO;
}
not_copied = copy_to_user(buf, data, to_copy);
kfree(data);
return to_copy - not_copied;
}
static int coa_close(struct inode *inode, struct file *filp)
{
if (!dev->p_dev->dev_node)
return -EIO;
SC14421_stop_dip(dev->sc14421_base);
dev->open = 0;
kfifo_reset(dev->rx_fifo);
kfifo_reset(dev->tx_fifo);
return 0;
}
static const struct file_operations coa_fops =
{
.owner = THIS_MODULE,
.open = coa_open,
.ioctl = coa_ioctl,
.poll = coa_poll,
.read = coa_read,
.release = coa_close,
};
/**********************************************************************/
static int com_on_air_suspend (struct pcmcia_device *link)
{
return 0;
}
static int com_on_air_resume (struct pcmcia_device *link)
{
return 0;
}
static irqreturn_t
com_on_air_irq_handler(int irq, void *dev_id)
{
struct coa_info * dev = dev_id;
jiffies_to_timespec(jiffies, &dev->irq_timestamp);
dev->irq_count++;
switch(dev->operation_mode & COA_MODEMASK)
{
case COA_MODE_FP:
/*station_irq_handler(dev); */
break;
case COA_MODE_PP:
/*phone_irq_handler(dev); */
break;
case COA_MODE_SNIFF:
sniffer_irq_handler(dev);
break;
default:
if (dev->sc14421_base)
SC14421_clear_interrupt(dev->sc14421_base);
}
return IRQ_HANDLED;
}
static int com_on_air_probe (struct pcmcia_device *link)
{
win_req_t req;
int ret;
dev->p_dev = link;
link->priv = dev;
link->dev_node = kzalloc(sizeof(*link->dev_node), GFP_KERNEL);
if (!link->dev_node)
return -ENOMEM;
link->devname = kzalloc(strlen(COA_DEVICE_NAME), GFP_KERNEL);
if (!link->devname)
{
ret = -ENOMEM;
goto probe_out_5;
}
sprintf(link->devname, COA_DEVICE_NAME);
sprintf(link->dev_node->dev_name, COA_DEVICE_NAME);
printk("com_on_air_cs: >>>>>>>>>>>>>>>>>>>>>>>>\n");
printk("com_on_air_cs: card in slot %s\n", link->devname);
if (link->prod_id[0])
printk("com_on_air_cs: prod_id[0] %s\n",
link->prod_id[0]);
if (link->prod_id[1])
printk("com_on_air_cs: prod_id[1] %s\n",
link->prod_id[1]);
if (link->prod_id[2])
printk("com_on_air_cs: prod_id[2] %s\n",
link->prod_id[2]);
if (link->prod_id[3])
printk("com_on_air_cs: prod_id[3] %s\n",
link->prod_id[3]);
link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
link->io.NumPorts1 = 16;
link->io.Attributes2 = 0;
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = com_on_air_irq_handler;
link->irq.Instance = dev;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.ConfigIndex = 1;
link->conf.Present = PRESENT_OPTION;
link->conf.ConfigBase = 0x1020;
req.Attributes = WIN_DATA_WIDTH_16 | WIN_ENABLE;
req.Base = 0;
req.Size = 0x1000;
req.AccessSpeed = 0;
ret = pcmcia_request_window(&link, &req, &link->win);
if (ret != CS_SUCCESS)
{
printk("couldn't pcmcia_request_window() = 0x%x\n", ret);
goto probe_out_4;
}
dev->links[0] = link;
dev->memsize[0] = req.Size;
dev->membase[0] = ioremap_nocache(req.Base, req.Size);
if (!dev->membase[0])
{
printk("com_on_air_cs: ERROR: couldn't ioremap()\n");
ret = -EIO;
goto probe_out_3;
}
printk("com_on_air_cs: ioremap()'d baseaddr %p\n", dev->membase[0]);
link->conf.Present = PRESENT_OPTION;
link->socket->functions = 0;
dev->irq_count = 0;
ret = pcmcia_request_irq(link, &link->irq);
if (ret != CS_SUCCESS)
{
printk("\ncom_on_air_cs: unable to allocate IRQ %d, ret=%x\n",
link->irq.AssignedIRQ, ret);
dev->irq = -1;
goto probe_out_2;
} else {
printk("com_on_air_cs: registered IRQ %d\n",
link->irq.AssignedIRQ);
dev->irq = link->irq.AssignedIRQ;
}
ret = pcmcia_request_configuration(link, &link->conf);
if (ret != CS_SUCCESS)
{
printk("could not pcmcia_request_configuration()\n");
goto probe_out_1;
}
ret = pcmcia_get_configuration_info(link, &(dev->config));
if (ret == CS_SUCCESS)
{
printk("com_on_air_cs: %svalid client.\n",
(dev->config.Attributes & CONF_VALID_CLIENT) ? "":"in");
printk("com_on_air_cs: type 0x%x\n",
link->socket->state);
printk("com_on_air_cs: function 0x%x\n",
dev->config.Function);
printk("com_on_air_cs: Attributes %d\n",
dev->config.Attributes);
printk("com_on_air_cs: Vcc %d\n",
dev->config.Vcc);
printk("com_on_air_cs: Vpp1 %d\n",
dev->config.Vpp1);
printk("com_on_air_cs: Vpp2 %d\n",
dev->config.Vpp2);
printk("com_on_air_cs: IntType %d\n",
dev->config.IntType);
printk("com_on_air_cs: ConfigBase 0x%x\n",
dev->config.ConfigBase);
printk("com_on_air_cs: Status %u, "
"Pin %u, "
"Copy %u, "
"Option %u, "
"ExtStatus %u\n",
dev->config.Status,
dev->config.Pin,
dev->config.Copy,
dev->config.Option,
dev->config.ExtStatus);
printk("com_on_air_cs: Present %d\n",
dev->config.Present);
printk("com_on_air_cs: CardValues 0x%x\n",
dev->config.CardValues);
printk("com_on_air_cs: AssignedIRQ 0x%x\n",
dev->config.AssignedIRQ);
printk("com_on_air_cs: IRQAttributes 0x%x\n",
dev->config.IRQAttributes);
printk("com_on_air_cs: BasePort1 0x%x\n",
dev->config.BasePort1);
printk("com_on_air_cs: NumPorts1 0x%x\n",
dev->config.NumPorts1);
printk("com_on_air_cs: Attributes1 0x%x\n",
dev->config.Attributes1);
printk("com_on_air_cs: BasePort2 0x%x\n",
dev->config.BasePort2);
printk("com_on_air_cs: NumPorts2 0x%x\n",
dev->config.NumPorts2);
printk("com_on_air_cs: Attributes2 0x%x\n",
dev->config.Attributes2);
printk("com_on_air_cs: IOAddrLines 0x%x\n",
dev->config.IOAddrLines);
printk("com_on_air_cs: has%s function_config\n",
(link->function_config) ? "":" no");
} else {
printk("com_on_air_cs: pcmcia_get_configuration_info() "
"failed\n");
goto probe_out_0;
}
set_device_configbase(dev->config.ConfigBase);
dev->sc14421_base = ((unsigned short*)(dev->membase[0]));
ret = get_card_id();
printk("com_on_air_cs: get_card_id() = %d\n", ret);
switch (ret)
{
case 0:
dev->radio_type = COA_RADIO_TYPE_II;
break;
case 1:
case 2:
dev->radio_type = COA_RADIO_TYPE_III;
break;
default:
printk("com_on_air_cs: ERROR; unknown radio type, "
"please update driver\n");
}
dev->card_id = ret;
printk("com_on_air_cs: -----------------------\n");
return 0;
probe_out_0:
pcmcia_disable_device(link);
probe_out_1:
free_irq(dev->irq, dev);
probe_out_2:
iounmap(dev->membase[0]);
probe_out_3:
pcmcia_release_window(link->win);
probe_out_4:
kfree(link->devname);
probe_out_5:
kfree(link->dev_node);
link->dev_node = NULL;
return ret;
}
static void com_on_air_remove(struct pcmcia_device *link)
{
int j;
printk("com_on_air_cs: COM-ON-AIR card ejected\n");
printk("com_on_air_cs: <<<<<<<<<<<<<<<<<<<<<<<\n");
if (dev->irq >= 0)
{
printk("com_on_air_cs: freeing interrupt %d\n",
dev->irq);
free_irq(dev->irq, dev);
}
for (j=0; j<2; j++)
{
if (dev->membase[j])
{
printk("com_on_air_cs: iounmap()ing membase[%d]\n", j);
iounmap(dev->membase[j]);
}
if (dev->links[j])
if (dev->links[j]->win)
{
printk("com_on_air_cs: releasing window %d\n",
j);
pcmcia_release_window(dev->links[j]->win);
}
}
printk("com_on_air_cs: pcmcia_disable_device()\n");
pcmcia_disable_device(link);
if (link->dev_node)
{
printk("com_on_air_cs: freeing dev_node\n");
kfree(link->dev_node);
link->dev_node = 0;
}
if (link->devname)
{
printk("com_on_air_cs: freeing devname\n");
kfree(link->devname);
link->devname = 0;
}
if (dev->sniffer_config)
{
printk("com_on_air_cs: freeing sniffer_config\n");
kfree(dev->sniffer_config);
dev->sniffer_config = 0;
}
}
static struct pcmcia_device_id com_on_air_ids[] =
{
/*
* the crc32 hashes below are generated by the tool in
* Documentation/pcmcia/devicetable.txt
*/
PCMCIA_DEVICE_PROD_ID12 ("DECTDataDevice", "PCMCIA F22",
0x11fe69e9, 0x253670b2),
PCMCIA_DEVICE_PROD_ID12 ("DECTDataDevice", "PCMCIA",
0x11fe69e9, 0x281f1c5d),
#if 1
PCMCIA_DEVICE_PROD_ID1234("DOSCH-AMAND", "MMAP PCMCIA",
"MXM500", "V1.00",
0x4bc552e7, 0x0df519bb,
0x09e43c7c, 0x3488c81a),
#endif
#if 0
There are more devices out there, I only own the above three.
an excerpt from win32 dna.inf:
%String1%=pcmcia.install,PCMCIA\DOSCH-AMAND-MMAP_PCMCIA-C7D7
%String1%=pcmcia.install,PCMCIA\Dosch-Amand-DECT_MultiMedia-BD0D
%String1%=pcmcia.install,PCMCIA\DOSCH_&_AMAND-DECT_MULTIMEDIA-1A9F
%String1%=pcmcia.install,PCMCIA\DECTDataDevice-F13-6433
%String1%=pcmcia.install,PCMCIA\DECTDataDevice-PCMCIA-0EF8
%String4%=pci.install,PCI\VEN_11E3&DEV_0001&SUBSYS_000111E3&REV_00
%String4%=pci.install,PCI\VEN_11E3&DEV_0001&SUBSYS_00011786&REV_32
%String4%=pci.install,PCI\VEN_1786&DEV_0001&SUBSYS_000111E3&REV_00
%String5%=freekey2.install,PCMCIA\DECTDataDevice-PCMCIA-FEF2
%String6%=freekey2.install,PCMCIA\DECTDataDevice-PCMCIA_F22-4BD3
%String6%=freekey2.install,PCMCIA\DECTDataDevice-PCMCIA_F22-BBD9
#endif
PCMCIA_DEVICE_NULL
};
MODULE_DEVICE_TABLE(pcmcia, com_on_air_ids);
/* returns an index into com_on_air_ids[] */
int get_card_id(void)
{
u32 hash[4] = { 0, 0, 0, 0};
int i;
int found = 0;
int ret = -1;
for (i=0; i<4; i++)
{
if (dev->p_dev->prod_id[i])
hash[i] = crc32(0,
dev->p_dev->prod_id[i],
strlen(dev->p_dev->prod_id[i]));
}
i = 0;
while(com_on_air_ids[i].match_flags) /* != PCMCIA_DEVICE_NULL */
{
if ( (hash[0] == com_on_air_ids[i].prod_id_hash[0]) &&
(hash[1] == com_on_air_ids[i].prod_id_hash[1]) &&
(hash[2] == com_on_air_ids[i].prod_id_hash[2]) &&
(hash[3] == com_on_air_ids[i].prod_id_hash[3]) )
{
found = 1;
ret = i;
}
i++;
}
if (!found)
printk("com_on_air_cs: ERROR: get_card_id() "
"didn't find card, please update driver\n");
return ret;
}
static struct pcmcia_driver coa_driver =
{
.owner = THIS_MODULE,
.drv =
{
.name = COA_DEVICE_NAME,
},
.probe = com_on_air_probe,
.remove = com_on_air_remove,
.suspend = com_on_air_suspend,
.resume = com_on_air_resume,
.id_table = com_on_air_ids,
};
static int __init init_com_on_air_cs(void)
{
int ret = 0;
printk(">>> loading " COA_DEVICE_NAME "\n");
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
ret = pcmcia_register_driver(&coa_driver);
if (ret != CS_SUCCESS)
{
printk("couldn't pcmcia_register_driver()\n");
goto init_out_3;
}
ret = register_chrdev(0xDEC, COA_DEVICE_NAME, &coa_fops);
if (ret < 0)
{
printk("couldn't register_chrdev()\n");
goto init_out_2;
}
spin_lock_init(&dev->rx_fifo_lock);
dev->rx_fifo = kfifo_alloc(COA_FIFO_SIZE, GFP_KERNEL,
&dev->rx_fifo_lock);
if (IS_ERR(dev->rx_fifo))
{
printk("couldn't kfifo_alloc(dev->rx_fifo)\n");
goto init_out_1;
}
spin_lock_init(&dev->tx_fifo_lock);
dev->tx_fifo = kfifo_alloc(COA_FIFO_SIZE, GFP_KERNEL,
&dev->tx_fifo_lock);
if (IS_ERR(dev->tx_fifo))
{
printk("couldn't kfifo_alloc(dev->tx_fifo)\n");
goto init_out_0;
}
return 0;
init_out_0:
kfifo_free(dev->rx_fifo);
init_out_1:
unregister_chrdev(0xDEC, COA_DEVICE_NAME);
init_out_2:
pcmcia_unregister_driver(&coa_driver);
init_out_3:
kfree(dev);
return ret;
}
static void __exit exit_com_on_air_cs(void)
{
printk("<<< unloading " COA_DEVICE_NAME "\n");
if (!dev) return;
unregister_chrdev(0xDEC, COA_DEVICE_NAME);
pcmcia_unregister_driver(&coa_driver);
kfifo_free(dev->rx_fifo);
kfifo_free(dev->tx_fifo);
kfree(dev);
}
module_init(init_com_on_air_cs);
module_exit(exit_com_on_air_cs);

View File

@ -0,0 +1,65 @@
/*
* com_on_air_cs - basic driver for the Dosch and Amand "com on air" cards
*
* 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.
*
* authors:
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
*
*/
#ifndef COM_ON_AIR_H
#define COM_ON_AIR_H
#include <linux/kernel.h>
#include <linux/module.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
struct coa_info
{
struct pcmcia_device *p_dev;
config_info_t config;
int open;
int irq;
int irq_count;
struct timespec irq_timestamp;
struct pcmcia_device *links[2];
caddr_t membase[2];
u_int memsize[2];
/* hardware configs */
unsigned short *sc14421_base;
unsigned int card_id; /* index into com_on_air_ids[] */
unsigned int radio_type;
unsigned int operation_mode;
/* struct fp_cfg *fp_config; */
/* struct pp_cfg *pp_config; */
struct sniffer_cfg *sniffer_config;
struct kfifo *rx_fifo;
spinlock_t rx_fifo_lock;
struct kfifo *tx_fifo;
spinlock_t tx_fifo_lock;
};
int get_card_id(void);
/* radio types */
#define COA_RADIO_TYPE_II 0
#define COA_RADIO_TYPE_III 1
#define COA_RADIO_FREEPAD 2
#endif

View File

@ -0,0 +1,45 @@
/*
* com_on_air_cs - basic driver for the Dosch and Amand "com on air" cards
*
* 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.
*
* authors:
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
*
*/
#ifndef COM_ON_AIR_USER_H
#define COM_ON_AIR_USER_H
/* operation modes */
#define COA_MODEMASK 0xFF00
#define COA_SUBMODEMASK 0x00FF
#define COA_MODE_IDLE 0x0000
#define COA_MODE_FP 0x0100
#define COA_MODE_PP 0x0200
#define COA_MODE_SNIFF 0x0300
#define COA_MODE_JAM 0x0400
#define COA_SUBMODE_SNIFF_SCANFP 0x0001
#define COA_SUBMODE_SNIFF_SCANPP 0x0002
#define COA_SUBMODE_SNIFF_SYNC 0x0003
/* ioctl */
#define COA_IOCTL_MODE 0xD000
#define COA_IOCTL_RADIO 0xD001
#define COA_IOCTL_RX 0xD002
#define COA_IOCTL_TX 0xD003
#define COA_IOCTL_CHAN 0xD004
#define COA_IOCTL_SLOT 0xD005
#define COA_IOCTL_RSSI 0xD006
#define COA_IOCTL_FIRMWARE 0xD007 /* request_firmware() */
#define COA_IOCTL_SETRFPI 0xD008
#endif

318
com-on-air_cs-linux/dect.c Normal file
View File

@ -0,0 +1,318 @@
/*
* com_on_air_cs - basic driver for the Dosch and Amand "com on air" cards
*
* 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.
*
* authors:
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
*
*/
#include "dect.h"
#define DECT_A_TA 0xe0
#define DECT_A_Q1 0x10
#define DECT_A_BA 0x0e
#define DECT_A_Q2 0x01
#define DECT_Q_TYPE 0x80
#define DECT_N_TYPE 0x60
#define DECT_P_TYPE 0xe0
#define DECT_Q_HEAD 0xf0
#define DECT_Q_HEAD_SSINFO 0x00 /* Static System info */
#define DECT_Q_HEAD_EXTRF1 0x20 /* Extended RF Carriers Part 1 */
#define DECT_Q_HEAD_FPC 0x30 /* Fixed Part Capabilities */
#define DECT_Q_HEAD_MULTIFN 0x60 /* Multi Frame Number */
#define DECT_Q_SSINFO_SLOT 0x0f
#define DECT_P_EXTFLAG 0x80
#define DECT_P_HEAD 0x70
#define DECT_P_HEAD_ZEROLP 0x00 /* Zero Length Page */
#define DECT_P_HEAD_SHORTLP 0x10 /* Short Length Page */
#define DECT_P_HEAD_FULLLP 0x20 /* Full Length Page */
#define DECT_P_HEAD_MACRES 0x30 /* MAC Resume Page */
#define DECT_P_HEAD_NOTLAST36 0x40 /* Not the Last 36 Bits of Long Page */
#define DECT_P_HEAD_FIRST36 0x50 /* First 36 Bit of Long Page */
#define DECT_P_HEAD_LAST26 0x60 /* Last 36 Bit of Long Page */
#define DECT_P_HEAD_ALLOFLP 0x70 /* All of Long Page (first and last) */
#define DECT_P_INFOTYPE 0xf0
#define DECT_P_IT_FILLBITS 0x00 /* Fill Bits */
#define DECT_P_IT_BFCIRCUIT 0x10 /* Blind Full Slot Information for \
Circuit Mode Service */
#define DECT_P_IT_OTHERBEAR 0x20 /* Other Bearer */
#define DECT_P_IT_RECOTHERBEAR 0x30 /* Recommended Other Bearer */
#define DECT_P_IT_GOODRFPBEAR 0x40 /* Good RFP Bearer */
#define DECT_P_IT_DUMMYCLPOS 0x50 /* Dummy or C/L Bearer Position */
#define DECT_P_IT_EXTMODULTYPE 0x60 /* Extended Modulation Type */
#define DECT_P_IT_ESCAPE 0x70 /* Escape */
#define DECT_P_IT_DUMMYCLBEARM 0x80 /* Dummy or C/L Bearer Marker */
#define DECT_P_IT_REPLACEINFO 0x90 /* Bearer Handover/Replacement \
Information */
#define DECT_P_IT_BEARERPOS_SN 0x0f /* Slot Number */
#define DECT_P_IT_BEARERPOS_SP 0xc0 /* Start Position */
#define DECT_P_IT_BEARERPOS_CN 0x3f /* Channel */
int dect_is_RFPI_Packet(unsigned char *packet)
{
if ((packet[5] & DECT_A_TA) == DECT_N_TYPE)
return 1;
return 0;
}
int dect_compare_RFPI(unsigned char *packet, unsigned char* RFPI)
{
if ((packet[5] & DECT_A_TA) == DECT_N_TYPE)
{
if (!memcmp(&packet[6], RFPI, 5))
return 1;
}
return 0;
}
int dect_get_slot(unsigned char *packet)
{
int slot = -1;
if ((packet[5] & DECT_A_TA) == DECT_Q_TYPE)
{
if ((packet[6] & DECT_Q_HEAD) == DECT_Q_HEAD_SSINFO)
{
slot = packet[6] & DECT_Q_SSINFO_SLOT;
}
}
return slot;
}
int dect_is_multiframe_number(unsigned char *packet)
{
if ((packet[5] & DECT_A_TA) == DECT_Q_TYPE)
{
/*printk("bl"); */
if ((packet[6] & DECT_Q_HEAD) == DECT_Q_HEAD_MULTIFN)
{
/*printk("aa\n"); */
return 1;
}
}
return 0;
}
int dect_is_fp_packet(unsigned char *packet)
{
if ( (packet[3] == 0xe9) && (packet[4] == 0x8a) )
return 1;
return 0;
}
int dect_is_pp_packet(unsigned char *packet)
{
if ( (packet[3] == 0x16) && (packet[4] == 0x75) )
return 1;
return 0;
}
int dect_update_slottable(struct dect_slot_info *slottable, int slot, unsigned char *packet)
{
if (slottable[slot].type == DECT_SLOTTYPE_SCAN)
{
printk("received packet on scanslot %u on carrier %u\n", slot, slottable[slot].channel);
slottable[slot].type = DECT_SLOTTYPE_CARRIER;
if (slottable[slot].channel == 0)
slottable[slot].channel = 9;
else
slottable[slot].channel--;
slottable[slot].errcnt = 0;
slottable[slot].update = 1;
if (slot > 12)
{
slottable[slot-12].type = DECT_SLOTTYPE_CARRIER;
if (slottable[slot-12].channel == 0)
slottable[slot-12].channel = 9;
else
slottable[slot-12].channel--;
slottable[slot-12].errcnt = 0;
slottable[slot].update = 1;
}
else
{
slottable[slot+12].type = DECT_SLOTTYPE_CARRIER;
if (slottable[slot+12].channel == 0)
slottable[slot+12].channel = 9;
else
slottable[slot+12].channel--;
slottable[slot+12].errcnt = 0;
slottable[slot].update = 1;
}
}
if (dect_is_fp_packet(packet))
{
switch(packet[5] & DECT_A_TA)
{
case DECT_P_TYPE:
if ( ( (packet[6] & DECT_P_HEAD) ==
DECT_P_HEAD_ZEROLP) ||
( (packet[6] & DECT_P_HEAD) ==
DECT_P_HEAD_SHORTLP) )
{
switch((packet[9] & DECT_P_INFOTYPE))
{
case DECT_P_IT_OTHERBEAR:
{
int newslot = (packet[9] & DECT_P_IT_BEARERPOS_SN) % 12;
slottable[newslot].active = 1;
slottable[newslot].channel = packet[10] & DECT_P_IT_BEARERPOS_CN;
slottable[newslot].type = DECT_SLOTTYPE_CARRIER;
slottable[newslot].errcnt = 0;
slottable[newslot].update = 1;
slottable[newslot+12].active = 1;
slottable[newslot+12].channel = packet[10] & DECT_P_IT_BEARERPOS_CN;
slottable[newslot+12].type = DECT_SLOTTYPE_CARRIER;
slottable[newslot+12].errcnt = 0;
slottable[newslot+12].update = 1;
/*printk("\n\nstation switching to slot %u channel %u\n\n",newslot, packet[10] & DECT_P_IT_BEARERPOS_CN); */
return 1;
}
case DECT_P_IT_BFCIRCUIT: /* set scanning slots */
{
int i, x, ret = 0;
unsigned int slots = (((unsigned int)(packet[9] & ~DECT_P_INFOTYPE)) << 8) | packet[10];
for (i=0; i<12; i++)
{
x = (slots & 0x800 ? 1:0);
slots <<= 1;
if (x && (!slottable[i].active))
{
printk("scanning on slot %u\n", i);
slottable[i].active = 1;
slottable[i].channel = 0; /* channel unknown at this position */
slottable[i].type = DECT_SLOTTYPE_SCAN;
slottable[i].errcnt = 0;
slottable[i].update = 1;
ret = 1;
}
if (x && (!slottable[i+12].active))
{
printk("scanning on slot %u\n", i + 12);
slottable[i+12].active = 1;
slottable[i+12].channel = 0; /* channel unknown at this position */
slottable[i+12].type = DECT_SLOTTYPE_SCAN;
slottable[i+12].errcnt = 0;
slottable[i+12].update = 1;
ret = 1;
}
}
return ret;
}
}
}
break;
case DECT_Q_TYPE:
if ((packet[6] & DECT_Q_HEAD) == DECT_Q_HEAD_SSINFO)
{
uint8_t pscan = packet[10];
int i, ret = 0;
for (i=0; i<24; i++)
{
if (slottable[i].active)
{
if (slottable[i].type == DECT_SLOTTYPE_SCAN)
{
/* if (pscan == 0)
pscan = 9;
else
pscan--;
*/
slottable[i].channel = pscan;
slottable[i].update = 1;
ret = 1;
}
}
}
return ret;
}
break;
}
}
return 0;
}
int dect_receive_error(struct dect_slot_info *slottable, int slot)
{
slottable[slot].errcnt++;
if (slottable[slot].type != DECT_SLOTTYPE_SCAN)
{
if (slottable[slot].errcnt > 32)
{
slottable[slot].active = 0;
slottable[slot].update = 1;
printk("slot %u on channel %u died\n", slot, slottable[slot].channel);
return 1;
}
}
return 0;
}
int dect_update_scanchannels(struct dect_slot_info *slottable)
{
int i, ret = 0;
for (i=0; i<24; i++) /* Increment primary scan channel */
{
if (slottable[i].active)
{
if (slottable[i].type == DECT_SLOTTYPE_SCAN)
{
slottable[i].channel++;
if (slottable[i].channel > 9)
slottable[i].channel = 0;
slottable[i].update = 1;
ret = 1;
/*printk("slot %u will now scan on carrier %u\n", i, slottable[i].channel); */
}
}
}
return ret;
}

View File

@ -0,0 +1,42 @@
/*
* com_on_air_cs - basic driver for the Dosch and Amand "com on air" cards
*
* 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.
*
* authors:
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
*
*/
#ifndef DECT_H
#define DECT_H
#include <linux/string.h>
#include <linux/kernel.h>
#define DECT_SLOTTYPE_CARRIER 0
#define DECT_SLOTTYPE_SCAN 1
struct dect_slot_info
{
uint8_t active;
uint8_t channel;
uint8_t type;
uint8_t errcnt;
uint8_t update;
};
int dect_is_RFPI_Packet(unsigned char *packet);
int dect_compare_RFPI(unsigned char *packet, unsigned char* RFPI);
int dect_get_slot(unsigned char *packet);
int dect_is_multiframe_number(unsigned char *packet);
int dect_is_fp_packet(unsigned char *packet);
int dect_is_pp_packet(unsigned char *packet);
int dect_update_slottable(struct dect_slot_info *slottable, int slot, unsigned char *packet);
int dect_receive_error(struct dect_slot_info *slottable, int slot);
int dect_update_scanchannels(struct dect_slot_info *slottable);
#endif

View File

@ -0,0 +1,161 @@
/*
* com_on_air_cs - basic driver for the Dosch and Amand "com on air" cards
*
* 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.
*
* authors:
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
*
*/
#ifndef DIP_OPCODE_H
#define DIP_OPCODE_H
#define BR 0x01
#define JMP 0x02
#define JMP1 0x03
#define RTN 0x04
#define BK_A1 0x05
#define WNTM1 0x06
#define WNTP1 0x07
#define WNT 0x08
#define WT 0x09
#define RFDIS 0x0a
#define RFEN 0x0b
#define LD_PTR 0x0c
#define SLOTZERO 0x0d
#define BK_A 0x0e
#define BK_C 0x0f
#define B_RST 0x20
#define B_ST2 0x21
#define B_XT 0x24
#define B_BT2 0x25
#define B_BTFU 0x25
#define B_XOFF 0x26
#define B_ON 0x27
#define B_XON 0x27
#define UNLCK 0x28
#define B_SR 0x29
#define B_XR 0x2b
#define EN_SL_ADJ 0x2c
#define B_BR2 0x2d
#define B_BRFU 0x2d
#define B_RINV 0x2e
#define B_RON 0x2f
#define B_ST 0x31
#define B_TX 0x31
#define B_AT 0x32
#define B_RC 0x33
#define B_BT 0x34
#define B_BTFP 0x35
#define B_BTP 0x35
#define B_AT2 0x37
#define B_WRS 0x39
#define B_AR 0x3a
#define B_BR 0x3c
#define B_BRP 0x3d
#define B_BRFP 0x3d
#define B_AR2 0x3f
#define D_RST 0x40
#define D_ON 0x42
#define D_OFF 0x43
#define D_PREP 0x44
#define WSC 0x48
#define D_LDK 0x50
#define D_LDS 0x57
#define D_WRS 0x5f
#define U_PSC 0x60
#define U_INT0 0x61
#define RCK_INT 0x62
#define RCK_EXT 0x63
#define B_WB_OFF 0x64
#define B_WB_ON 0x65
#define CLK1 0x66
#define CLK3 0x67
#define U_CK8 0x68
#define U_CK4 0x69
#define U_CK2 0x6a
#define U_INT1 0x6b
#define U_CK1 0x6c
#define U_INT2 0x6d
#define U_INT3 0x6f
#define A_RCV0 0x80
#define A_RCV36 0x82
#define A_RCV30 0x83
#define A_RCV24 0x84
#define A_RCV18 0x85
#define A_RCV12 0x86
#define A_RCV6 0x87
#define A_RCV33 0x8a
#define A_RCV27 0x8b
#define A_RCV21 0x8c
#define A_RCV15 0x8d
#define A_RCV9 0x8e
#define A_RCV3 0x8f
#define MEN3N 0xa2
#define MEN3 0xa3
#define MEN1N 0xa4
#define MEN1 0xa5
#define MEN2N 0xa6
#define MEN2 0xa7
#define M_RD 0xa8
#define M_RST 0xa9
#define M_WRS 0xb8
#define M_WR 0xb9
#define A_RST 0xc0
#define A_MUTE 0xc1
#define A_STOFF 0xc2
#define A_ALAW 0xc3
#define A_DT 0xc4
#define A_NORM 0xc5
#define A_LDR 0xc6
#define A_LDW 0xc7
#define A_LIN 0xc8
#define A_MTOFF 0xc9
#define A_MUTE1 0xca
#define A_MTOFF1 0xcb
#define A_STON 0xcc
#define A_DT1 0xcd
#define A_LDR1 0xce
#define A_LDW1 0xcf
#define A_STRN 0xe0
#define P_LD 0xe8
#define P_EN 0xe9
#define P_SC 0xea
#define A_RST1 0xeb
#define P_LDL 0xec
#define P_LDH 0xed
#define C_ON 0xee
#define C_OFF 0xef
#define C_LD 0xfa
#endif

View File

@ -0,0 +1 @@
extern unsigned char _fw[509];

View File

@ -0,0 +1,37 @@
CFLAGS=-Wall -O2
FW=sc14421_firmware
FW1=sc14421_II_sniff_scan
FW2=sc14421_II_sniff_sync
ALL_FW=$(FW1) $(FW2)
BIN2C=./bin2c
all: ../$(FW).h ../$(FW).c
../$(FW).h: $(FW1).h $(FW2).h
cat sc14421_header.h $^ sc14421_footer.h > $@
../$(FW).c: $(FW1).c $(FW2).c
cat $^ > $@
$(FW1).c $(FW2).c: $(FW1).bin $(FW2).bin $(BIN2C)
$(BIN2C) $(@:.c=.bin) $(@:.c=)_fw > $@
%.bin: %.p
p2bin $^ $@ -r 0-507
%.p: %.asm
asl $^
$(FW1).h $(FW2).h:
echo "extern unsigned char $(@:.h=)_fw[509];" > $@
clean:
rm -f ../$(FW).h ../$(FW).c $(BIN2C)
rm -f $(foreach f,$(ALL_FW),$f.c)
rm -f $(foreach f,$(ALL_FW),$f.h)
rm -f $(foreach f,$(ALL_FW),$f.bin)

View File

@ -0,0 +1,55 @@
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#define HEADER_FMT \
"\n\n" \
"/* automatically generated file\n" \
" * DO NOT EDIT\n" \
" * edit firmware/filename.asm instead */\n" \
"\n" \
"unsigned char %s[] = {\n"
#define FOOTER "};\n"
int main(int argc, char *argv[])
{
if(argc<3)
{
printf("usage: bin2c bin-file varname > c-file\n");
exit(1);
}
int f = open(argv[1], O_RDONLY);
if(f<0)
{
printf("cant open(\"%s\"): %s\n", argv[1], strerror(errno));
exit(1);
}
printf(HEADER_FMT, argv[2]);
uint32_t wordcount = 0;
uint16_t w;
while (2 == read(f, &w, 2))
{
if (!wordcount)
printf("\t");
else
if (!(wordcount % 4))
printf(",\n\t");
else
printf(", ");
printf("0x%.2x, 0x%.2x", (w&0xff00)>>8, w&0xff);
wordcount++;
}
printf(FOOTER);
close(f);
return 0;
}

View File

@ -0,0 +1,110 @@
CPU SC14421
ORG 0
BR Start
PB_LED EQU 0x80
PB_RX_ON EQU 0x40
PB_TX_ON EQU 0x10
PB_RADIOPOWER EQU 0x04
PB_DCTHRESHOLD EQU 0x02
PB_RSSI EQU 0x01
;-------------------------------------------------------------
Start: B_RST
BK_C 0x00
C_LD 0x10
WT 10
B_RC 0x00
WT 8
B_RST
C_ON
WT 10
P_EN
P_LD PB_RADIOPOWER
RCK_INT
RFEN
;-------------------------------------------------------------
BK_C 0x20
JMP RFInit
TryAgain: JMP label_B1
WT 250
P_SC 0x20
P_LDH PB_RX_ON|PB_DCTHRESHOLD
UNLCK
WT 64
B_XOFF
B_SR
WNT 20
JMP1 SFieldFound
BR TryAgain
;-------------------------------------------------------------
SFieldFound: WNT 23
P_SC 0x00
JMP ReceiveSlot
U_INT0
BR TryAgain
;-------------------------------------------------------------
ReceiveSlot: JMP label_B1
JMP RecvPP
WT 1
B_BRFU 0x0e
WT 255
WT 73
P_LDH PB_RSSI
P_LDL PB_RX_ON
B_WRS 0x00
WT 6
B_RST
P_LDL PB_RX_ON|PB_TX_ON
WT 5
RTN
;-------------------------------------------------------------
RecvPP: P_LDH PB_RX_ON
P_LDL PB_RSSI
WT 34
WNT 1
B_XON
P_LDH PB_DCTHRESHOLD
WT 5
B_SR
EN_SL_ADJ
WT 12
P_LDL PB_DCTHRESHOLD
WT 33
B_AR2 0x06
WT 61
RTN
;-------------------------------------------------------------
RFInit: RFEN
MEN1N
WT 2
M_WR 0x4A
WT 25
M_RST
MEN1
MEN1N
M_WR 0x4D
WT 10
M_RST
MEN1
RTN
;-------------------------------------------------------------
label_B1: B_RST
B_RC 0x58
WT 8
MEN2
WT 182
MEN2N
WT 16
RTN
;-------------------------------------------------------------

View File

@ -0,0 +1,298 @@
CPU SC14421
ORG 0
BR Start
PB_LED EQU 0x80
PB_RX_ON EQU 0x40
PB_TX_ON EQU 0x10
PB_RADIOPOWER EQU 0x04
PB_DCTHRESHOLD EQU 0x02
PB_RSSI EQU 0x01
;-------------------------------------------------------------
Start: BR InitDIP
;-------------------------------------------------------------
SlotTable: SLOTZERO
JP0: BK_C 0x20
PP0: WNT 2
JP2: BK_C 0x30
PP2: WNT 2
JP4: BK_C 0x40
PP4: WNT 2
JP6: BK_C 0x50
PP6: WNT 2
JP8: BK_C 0x60
PP8: WNT 2
JP10: BK_C 0x70
PP10: WNT 2
U_INT0
JP12: BK_C 0x80
PP12: WNT 2
JP14: BK_C 0x90
PP14: WNT 2
JP16: BK_C 0xA0
PP16: WNT 2
JP18: BK_C 0xB0
PP18: WNT 2
JP20: BK_C 0xC0
PP20: WNT 2
JP22: BK_C 0xD0
PP22: WNT 2
U_INT3
P_LDL 0x80
BR SlotTable
;-------------------------------------------------------------
label_28: JMP RFInit
JMP label_B1
BR label_2D
;-------------------------------------------------------------
JMP RFInit
JMP label_B3
label_2D: JMP RecvPP
WT 1
B_BRFU 0x0E
JMP label_6B
BR label_51
;-------------------------------------------------------------
JMP RFInit
JMP label_B1
BR label_37
;-------------------------------------------------------------
JMP RFInit
JMP label_B3
label_37: JMP RecvPP
BR label_92
;-------------------------------------------------------------
JMP RFInit
JMP label_B1
BR label_3E
;-------------------------------------------------------------
JMP RFInit
JMP label_B3
label_3E: JMP label_70
WT 1
B_BTFU 0x0E
JMP label_7C
BR label_54
;-------------------------------------------------------------
JMP RFInit
JMP label_B3
JMP label_70
WT 1
B_BT 0x0E
JMP label_7F
BR label_53
;-------------------------------------------------------------
JMP RFInit
JMP label_B1
BR label_4F
;-------------------------------------------------------------
JMP RFInit
JMP label_B3
label_4F: JMP label_70
BR label_9B
;-------------------------------------------------------------
label_51: B_WRS 0x00
WT 6
label_53: B_RST
label_54: P_LDL 0x50
WT 5
WNT 1
label_57: RTN
;-------------------------------------------------------------
label_58: B_RST
P_LDL 0x50
BR label_57
;-------------------------------------------------------------
RecvPP: P_LDH 0x40
P_LDL PB_RSSI
WT 25
WNT 1
WT 9
B_XON
P_LDH 0x02
WT 5
B_SR
EN_SL_ADJ
WT 12
P_LDL 0x02
WT 33
B_AR2 0x06
WT 61
RTN
;-------------------------------------------------------------
label_6B: WT 249
WT 79
label_6D: P_LDH PB_RSSI
P_LDL 0x40
RTN
;-------------------------------------------------------------
label_70: P_LDH 0x00
WT 40
B_RST
B_RC 0x50
WNT 1
B_ST 0x00
WT 1
P_LDH 0x10
WT 37
B_AT2 0x06
WT 61
RTN
;-------------------------------------------------------------
label_7C: WT 249
WT 84
B_RST
label_7F: P_LDL 0x10
WT 8
P_LDL 0x00
RTN
;-------------------------------------------------------------
label_83: B_XON
WT 15
B_XOFF
WT 61
RTN
;-------------------------------------------------------------
label_88: WT 61
JMP label_83
JMP label_83
JMP label_83
JMP label_83
JMP label_83
WT 1
B_XON
WT 11
RTN
;-------------------------------------------------------------
label_92: B_BR 0x0E
JMP label_88
WT 3
B_XR
WT 6
JMP label_6D
B_WRS 0x00
WT 6
BR label_58
;-------------------------------------------------------------
label_9B: B_BT 0x0E
WT 3
JMP label_88
B_XT
WT 13
B_RST
JMP label_7F
BR label_58
;-------------------------------------------------------------
RFInit: RFEN
MEN1N
WT 1
WT 1
M_WR 0x4A
WT 25
M_RST
MEN1
MEN1N
M_WR 0x4D
WT 10
M_RST
MEN1
RTN
;-------------------------------------------------------------
label_B1: P_LDL 0x20
BR label_B5
;-------------------------------------------------------------
label_B3: P_LDH 0x20
BR label_B5
;-------------------------------------------------------------
label_B5: B_RST
B_RC 0x58
WT 8
MEN2
WT 118
WT 64
MEN2N
P_LDH 0x00
WT 16
RTN
;-------------------------------------------------------------
PPSync: BK_C 0x20
label_C0: JMP RFInit
JMP label_B1
WT 250
P_SC 0x20
P_LDH PB_RX_ON|PB_DCTHRESHOLD
UNLCK
WT 64
B_XOFF
B_SR
WNT 20
JMP1 SFieldFound
B_RST
U_INT1
WNT 23
BR label_C0
;-------------------------------------------------------------
SFieldFound: WNT 23
P_SC 0x00
label_D1: JMP label_28
U_INT0
WNT 22
label_D4: BR label_C0
;-------------------------------------------------------------
InitDIP: B_RST
BK_C 0x00
C_LD 0x10
WT 10
B_RC 0x00
WT 8
B_RST
BK_A 0x00
A_LDR 0x8C
A_LDW 0xB4
BK_A1 0x00
A_LDR1 0x0C
A_LDW1 0x34
C_ON
A_NORM
WT 10
P_EN
P_LD 0x04
RCK_INT
RFEN
BR PPSync
;-------------------------------------------------------------
SHARED PP0,PP2,PP4,PP6,PP8,PP10,PP12,PP14,PP16,PP18,PP20,PP22
SHARED JP0,JP2,JP4,JP6,JP8,JP10,JP12,JP14,JP16,JP18,JP20,JP22
SHARED label_D1,label_D4,label_28

View File

@ -0,0 +1,2 @@
#endif

View File

@ -0,0 +1,3 @@
#ifndef SC14421_FIRMWARE_H
#define SC14421_FIRMWARE_H

View File

@ -0,0 +1,146 @@
/*
* com_on_air_cs - basic driver for the Dosch and Amand "com on air" cards
*
* 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.
*
* authors:
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <asm/io.h>
#include "sc14421.h"
#include "dip_opcodes.h"
static u_int deviceConfigBase = 0;
void set_device_configbase(u_int configBase)
{
deviceConfigBase = configBase;
}
void wait_4_IO_cycles()
{
if (!deviceConfigBase) {
printk("error: config base not set!\n");
return;
}
inb_p(deviceConfigBase);
inb_p(deviceConfigBase);
inb_p(deviceConfigBase);
inb_p(deviceConfigBase);
}
void to_dip(uint16_t *dst, unsigned char *src, int length)
{
int i;
for (i=0; i<length; i++)
#if defined(__LITTLE_ENDIAN)
*(dst++) = *(src++);
#elif defined(__BIG_ENDIAN)
*(dst++) =s wab16(*(src++));
#else
#error "endianness not defined"
#endif
}
void from_dip(unsigned char *dst, volatile uint16_t *src, int length)
{
int i;
for (i=0; i<length; i++)
#if defined(__LITTLE_ENDIAN)
*(dst++) = *(src++);
#elif defined(__BIG_ENDIAN)
*(dst++) = swab16(*(src++));
#else
#error "endianness not defined"
#endif
}
void SC14421_switch_to_bank(volatile uint16_t *sc14421_base, unsigned char bank)
{
SC14421_WRITE(511, bank);
wait_4_IO_cycles();
}
void SC14421_stop_dip(volatile uint16_t *sc14421_base)
{
SC14421_switch_to_bank(sc14421_base, SC14421_DIPSTOPPED);
}
void SC14421_write_cmd(volatile uint16_t *sc14421_base, int label, unsigned char opcode, unsigned char operand)
{
SC14421_WRITE(label*2 + 0, opcode);
SC14421_WRITE(label*2 + 1, operand);
}
unsigned char SC14421_clear_interrupt(volatile uint16_t *sc14421_base)
{
unsigned char int1, int2, cnt = 0;
int1 = SC14421_READ(511);
if (int1 == 0xff)
return 0;
int2 = int1 & 0x0f;
while (int1)
{
cnt++;
if (!cnt)
return 0;
int1 = SC14421_READ(511) & 0x0f;
int2 |= int1;
}
return (int2 & 0x0f);
}
int SC14421_check_RAM(volatile uint16_t *sc14421_base)
{
unsigned char bank;
int ErrCnt;
int i;
unsigned char x;
ErrCnt = 0;
for (i=0; i<8; i++)
{
bank = (4*i) | 0x80;
SC14421_switch_to_bank(sc14421_base, bank);
for (x=0; x<254; x++)
SC14421_WRITE(x, (x+i) & 0xff);
}
for (i=0; i<8; i++)
{
bank = (4*i)|0x80;
SC14421_switch_to_bank(sc14421_base, bank);
for (x=0; x<254; x++)
{
if ( (SC14421_READ(x) & 0xff) != ((x+i) & 0xff) )
{
printk("error bank:%.2x %.2x - %.2x != %.2x \n", bank, x, SC14421_READ(x), (unsigned char)((x+i) & 0xff));
ErrCnt++;
}
SC14421_WRITE(x, 0);
}
}
return ErrCnt;
}

View File

@ -0,0 +1,50 @@
/*
* com_on_air_cs - basic driver for the Dosch and Amand "com on air" cards
*
* 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.
*
* authors:
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
*
*/
#ifndef SC14421_H
#define SC14421_H
#include <linux/byteorder/swab.h>
#define SC14421_DIPSTOPPED 0x80
#define SC14421_RAMBANK0 0x00
#define SC14421_RAMBANK1 0x04
#define SC14421_RAMBANK2 0x08
#define SC14421_RAMBANK3 0x0c
#define SC14421_RAMBANK4 0x10
#define SC14421_RAMBANK5 0x14
#define SC14421_RAMBANK6 0x18
#define SC14421_RAMBANK7 0x1c
#define SC14421_CODEBANK 0x20
#if defined(__LITTLE_ENDIAN)
# define SC14421_READ(offset) sc14421_base[(offset)]
# define SC14421_WRITE(offset, value) { sc14421_base[(offset)] = (value); }
#elif defined(__BIG_ENDIAN)
# define SC14421_READ(offset) swab16(sc14421_base[(offset)])
# define SC14421_WRITE(offset, value) { sc14421_base[(offset)] = swab16(value); }
#else
# error "could not determine endianness"
#endif
void set_device_configbase(u_int);
void wait_4_IO_cycles(void);
void to_dip(unsigned short *dst, unsigned char *src, int length);
void from_dip(unsigned char *dst, volatile uint16_t *src, int length);
void SC14421_switch_to_bank(volatile uint16_t *sc14421_base, unsigned char bank);
void SC14421_stop_dip(volatile uint16_t *sc14421_base);
void SC14421_write_cmd(volatile uint16_t *sc14421_base, int label, unsigned char opcode, unsigned char operand);
unsigned char SC14421_clear_interrupt(volatile uint16_t *sc14421_base);
int SC14421_check_RAM(volatile uint16_t *sc14421_base);
#endif

View File

@ -0,0 +1,142 @@
/* automatically generated file
* DO NOT EDIT
* edit firmware/filename.asm instead */
unsigned char sc14421_II_sniff_scan_fw[] = {
0x01, 0x01, 0x20, 0x00, 0x0f, 0x00, 0xfa, 0x10,
0x09, 0x0a, 0x33, 0x00, 0x09, 0x08, 0x20, 0x00,
0xee, 0x00, 0x09, 0x0a, 0xe9, 0x00, 0xe8, 0x04,
0x62, 0x00, 0x0b, 0x00, 0x0f, 0x20, 0x02, 0x3d,
0x02, 0x4a, 0x09, 0xfa, 0xea, 0x20, 0xed, 0x42,
0x28, 0x00, 0x09, 0x40, 0x26, 0x00, 0x29, 0x00,
0x08, 0x14, 0x03, 0x1b, 0x01, 0x10, 0x08, 0x17,
0xea, 0x00, 0x02, 0x20, 0x61, 0x00, 0x01, 0x10,
0x02, 0x4a, 0x02, 0x2e, 0x09, 0x01, 0x2d, 0x0e,
0x09, 0xff, 0x09, 0x49, 0xed, 0x01, 0xec, 0x40,
0x39, 0x00, 0x09, 0x06, 0x20, 0x00, 0xec, 0x50,
0x09, 0x05, 0x04, 0x00, 0xed, 0x40, 0xec, 0x01,
0x09, 0x22, 0x08, 0x01, 0x27, 0x00, 0xed, 0x02,
0x09, 0x05, 0x29, 0x00, 0x2c, 0x00, 0x09, 0x0c,
0xec, 0x02, 0x09, 0x21, 0x3f, 0x06, 0x09, 0x3d,
0x04, 0x00, 0x0b, 0x00, 0xa4, 0x00, 0x09, 0x02,
0xb9, 0x4a, 0x09, 0x19, 0xa9, 0x00, 0xa5, 0x00,
0xa4, 0x00, 0xb9, 0x4d, 0x09, 0x0a, 0xa9, 0x00,
0xa5, 0x00, 0x04, 0x00, 0x20, 0x00, 0x33, 0x58,
0x09, 0x08, 0xa7, 0x00, 0x09, 0xb6, 0xa6, 0x00,
0x09, 0x10, 0x04, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff};
/* automatically generated file
* DO NOT EDIT
* edit firmware/filename.asm instead */
unsigned char sc14421_II_sniff_sync_fw[] = {
0x01, 0x01, 0x01, 0xcc, 0x0d, 0x00, 0x0f, 0x20,
0x08, 0x02, 0x0f, 0x30, 0x08, 0x02, 0x0f, 0x40,
0x08, 0x02, 0x0f, 0x50, 0x08, 0x02, 0x0f, 0x60,
0x08, 0x02, 0x0f, 0x70, 0x08, 0x02, 0x61, 0x00,
0x0f, 0x80, 0x08, 0x02, 0x0f, 0x90, 0x08, 0x02,
0x0f, 0xa0, 0x08, 0x02, 0x0f, 0xb0, 0x08, 0x02,
0x0f, 0xc0, 0x08, 0x02, 0x0f, 0xd0, 0x08, 0x02,
0x6f, 0x00, 0xec, 0x80, 0x01, 0x02, 0x02, 0x9a,
0x02, 0xa8, 0x01, 0x24, 0x02, 0x9a, 0x02, 0xaa,
0x02, 0x52, 0x09, 0x01, 0x2d, 0x0e, 0x02, 0x62,
0x01, 0x48, 0x02, 0x9a, 0x02, 0xa8, 0x01, 0x2e,
0x02, 0x9a, 0x02, 0xaa, 0x02, 0x52, 0x01, 0x89,
0x02, 0x9a, 0x02, 0xa8, 0x01, 0x35, 0x02, 0x9a,
0x02, 0xaa, 0x02, 0x67, 0x09, 0x01, 0x25, 0x0e,
0x02, 0x73, 0x01, 0x4b, 0x02, 0x9a, 0x02, 0xaa,
0x02, 0x67, 0x09, 0x01, 0x34, 0x0e, 0x02, 0x76,
0x01, 0x4a, 0x02, 0x9a, 0x02, 0xa8, 0x01, 0x46,
0x02, 0x9a, 0x02, 0xaa, 0x02, 0x67, 0x01, 0x92,
0x39, 0x00, 0x09, 0x06, 0x20, 0x00, 0xec, 0x50,
0x09, 0x05, 0x08, 0x01, 0x04, 0x00, 0x20, 0x00,
0xec, 0x50, 0x01, 0x4e, 0xed, 0x40, 0xec, 0x01,
0x09, 0x19, 0x08, 0x01, 0x09, 0x09, 0x27, 0x00,
0xed, 0x02, 0x09, 0x05, 0x29, 0x00, 0x2c, 0x00,
0x09, 0x0c, 0xec, 0x02, 0x09, 0x21, 0x3f, 0x06,
0x09, 0x3d, 0x04, 0x00, 0x09, 0xf9, 0x09, 0x4f,
0xed, 0x01, 0xec, 0x40, 0x04, 0x00, 0xed, 0x00,
0x09, 0x28, 0x20, 0x00, 0x33, 0x50, 0x08, 0x01,
0x31, 0x00, 0x09, 0x01, 0xed, 0x10, 0x09, 0x25,
0x37, 0x06, 0x09, 0x3d, 0x04, 0x00, 0x09, 0xf9,
0x09, 0x54, 0x20, 0x00, 0xec, 0x10, 0x09, 0x08,
0xec, 0x00, 0x04, 0x00, 0x27, 0x00, 0x09, 0x0f,
0x26, 0x00, 0x09, 0x3d, 0x04, 0x00, 0x09, 0x3d,
0x02, 0x7a, 0x02, 0x7a, 0x02, 0x7a, 0x02, 0x7a,
0x02, 0x7a, 0x09, 0x01, 0x27, 0x00, 0x09, 0x0b,
0x04, 0x00, 0x3c, 0x0e, 0x02, 0x7f, 0x09, 0x03,
0x2b, 0x00, 0x09, 0x06, 0x02, 0x64, 0x39, 0x00,
0x09, 0x06, 0x01, 0x4f, 0x34, 0x0e, 0x09, 0x03,
0x02, 0x7f, 0x24, 0x00, 0x09, 0x0d, 0x20, 0x00,
0x02, 0x76, 0x01, 0x4f, 0x0b, 0x00, 0xa4, 0x00,
0x09, 0x01, 0x09, 0x01, 0xb9, 0x4a, 0x09, 0x19,
0xa9, 0x00, 0xa5, 0x00, 0xa4, 0x00, 0xb9, 0x4d,
0x09, 0x0a, 0xa9, 0x00, 0xa5, 0x00, 0x04, 0x00,
0xec, 0x20, 0x01, 0xac, 0xed, 0x20, 0x01, 0xac,
0x20, 0x00, 0x33, 0x58, 0x09, 0x08, 0xa7, 0x00,
0x09, 0x76, 0x09, 0x40, 0xa6, 0x00, 0xed, 0x00,
0x09, 0x10, 0x04, 0x00, 0x0f, 0x20, 0x02, 0x9a,
0x02, 0xa8, 0x09, 0xfa, 0xea, 0x20, 0xed, 0x42,
0x28, 0x00, 0x09, 0x40, 0x26, 0x00, 0x29, 0x00,
0x08, 0x14, 0x03, 0xc6, 0x20, 0x00, 0x6b, 0x00,
0x08, 0x17, 0x01, 0xb7, 0x08, 0x17, 0xea, 0x00,
0x02, 0x1f, 0x61, 0x00, 0x08, 0x16, 0x01, 0xb7,
0x20, 0x00, 0x0f, 0x00, 0xfa, 0x10, 0x09, 0x0a,
0x33, 0x00, 0x09, 0x08, 0x20, 0x00, 0x0e, 0x00,
0xc6, 0x8c, 0xc7, 0xb4, 0x05, 0x00, 0xce, 0x0c,
0xcf, 0x34, 0xee, 0x00, 0xc5, 0x00, 0x09, 0x0a,
0xe9, 0x00, 0xe8, 0x04, 0x62, 0x00, 0x0b, 0x00,
0x01, 0xb6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff};

View File

@ -0,0 +1,7 @@
#ifndef SC14421_FIRMWARE_H
#define SC14421_FIRMWARE_H
extern unsigned char sc14421_II_sniff_scan_fw[509];
extern unsigned char sc14421_II_sniff_sync_fw[509];
#endif

View File

@ -0,0 +1,828 @@
/*
* com_on_air_cs - basic driver for the Dosch and Amand "com on air" cards
*
* 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.
*
* authors:
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kfifo.h>
#include "sc14421.h"
#include "dip_opcodes.h"
#include "com_on_air.h"
#include "sc14421_sniffer.h"
#include "sc14421_firmware.h"
#include "dect.h"
/* dip config register control */
unsigned char scan_init1[] = {0x27,0x00,0xff,0x00,0x5f,0x04,0x00};
unsigned char scan_init2[] = {0xc2,0x05,0x00,0x03,0x00,0x00};
/* hf register type II card */
unsigned char scan_II_init3[] = {0x54,0x80,0x09/* patch */,0xa0,0x00,0x00};
/* hf register type III card */
unsigned char scan_III_init3[] = {0x54,0x80,0x09/* patch */,0xa0,0x00,0x00};
/* hf register */
unsigned char scan_init4[] = {0x15,0xa0,0xff,0x00/* &0x3f */,0x5f,0x04,0x00};
/* dip control */
unsigned char scan_init5[] = {0x27,0x00,0xff,0x00,0x5f,0x05,0x00};
/* dip control */
unsigned char sync_init1[] = {0x27,0x00,0xff,0x00,0x5f,0x04,0x00};
unsigned char sync_init2[] = {0xc2,0x05,0x00,0x03,0x00,0x00};
/* hf register type II card */
unsigned char sync_II_init3[] = {0x54,0x80,0x09/* patch */,0xa0,0x00,0x00};
/* hf register type III card */
unsigned char sync_III_init3[] = {0x54,0x80,0x09/* patch */,0xa0,0x00,0x00};
/* hf register */
unsigned char sync_init4[] = {0x15,0xa0,0xff,0x00/* &0x3f */,0x5f,0x04,0x00};
/* dip control */
unsigned char sync_init5[] = {0x27,0x00,0xff,0x00,0x5f,0x05,0x00};
unsigned char fppacket[53] = {0xAA,0xAA,0xAA,0xE9,0x8A};
unsigned char pppacket[53] = {0x55,0x55,0x55,0x16,0x75};
/* FIXME:auto-generate all this stuff */
#define PP0 0x4
#define PP2 0x6
#define PP4 0x8
#define PP6 0xA
#define PP8 0xC
#define PP10 0xE
#define PP12 0x11
#define PP14 0x13
#define PP16 0x15
#define PP18 0x17
#define PP20 0x19
#define PP22 0x1B
#define JP0 0x3
#define JP2 0x5
#define JP4 0x7
#define JP6 0x9
#define JP8 0xB
#define JP10 0xD
#define JP12 0x10
#define JP14 0x12
#define JP16 0x14
#define JP18 0x16
#define JP20 0x18
#define JP22 0x1A
#define sync_label_D1 0xC8
#define sync_label_D4 0xCB
#define sync_label_28 0x1F
int sync_jumptable[] = {
JP0, 0,
JP2, 0,
JP4, 0,
JP6, 0,
JP8, 0,
JP10, 0,
JP12, 0,
JP14, 0,
JP16, 0,
JP18, 0,
JP20, 0,
JP22, 0
};
int sync_patchtable[] = {
PP0, 0,
PP2, 0,
PP4, 0,
PP6, 0,
PP8, 0,
PP10, 0,
PP12, 0,
PP14, 0,
PP16, 0,
PP18, 0,
PP20, 0,
PP22, 0
};
/* FIXME:end */
int sync_banktable[] = {
SC14421_RAMBANK1,
SC14421_RAMBANK1,
SC14421_RAMBANK1,
SC14421_RAMBANK1,
SC14421_RAMBANK2,
SC14421_RAMBANK2,
SC14421_RAMBANK2,
SC14421_RAMBANK2,
SC14421_RAMBANK3,
SC14421_RAMBANK3,
SC14421_RAMBANK3,
SC14421_RAMBANK3,
SC14421_RAMBANK4,
SC14421_RAMBANK4,
SC14421_RAMBANK4,
SC14421_RAMBANK4,
SC14421_RAMBANK5,
SC14421_RAMBANK5,
SC14421_RAMBANK5,
SC14421_RAMBANK5,
SC14421_RAMBANK6,
SC14421_RAMBANK6,
SC14421_RAMBANK6,
SC14421_RAMBANK6
};
void sniffer_init(struct coa_info *dev)
{
int ret;
SC14421_switch_to_bank(
dev->sc14421_base,
SC14421_DIPSTOPPED | SC14421_CODEBANK
);
ret = SC14421_check_RAM(dev->sc14421_base);
if (ret)
printk("Found %u memory r/w errors \n\n", ret);
switch(dev->sniffer_config->snifftype)
{
case SNIFF_SCANFP:
case SNIFF_SCANPP:
sniffer_init_sniff_scan(dev);
break;
case SNIFF_SYNC:
sniffer_init_sniff_sync(dev);
break;
}
}
void sniffer_init_sniff_scan(struct coa_info *dev)
{
uint16_t *sc14421_base = dev->sc14421_base;
/* printk("loading sniff_scan firmware\n"); */
SC14421_switch_to_bank(
sc14421_base,
SC14421_DIPSTOPPED | SC14421_CODEBANK
);
to_dip(
sc14421_base,
sc14421_II_sniff_scan_fw,
ARRAY_SIZE(sc14421_II_sniff_scan_fw));
SC14421_clear_interrupt(sc14421_base);
/* set channel */
switch(dev->radio_type)
{
case COA_RADIO_TYPE_II:
scan_II_init3[0] =
(scan_II_init3[0] & 0xC1) |
((10 - dev->sniffer_config->channel) << 1);
break;
default:
printk("ERROR: this radio type is currently not "
"supported. please update the driver\n");
}
if (dev->sniffer_config->snifftype == SNIFF_SCANPP)
{
scan_init1[0] &= 0xFE;
scan_init5[0] &= 0xFE;
}
else
{
scan_init1[0] |= 0x01;
scan_init5[0] |= 0x01;
}
SC14421_switch_to_bank(
sc14421_base,
SC14421_DIPSTOPPED | SC14421_RAMBANK0
);
to_dip(
sc14421_base + 0x00,
scan_init1,
ARRAY_SIZE(scan_init1));
to_dip(
sc14421_base + 0x10,
scan_init2,
ARRAY_SIZE(scan_init2)
);
SC14421_switch_to_bank(
sc14421_base,
SC14421_DIPSTOPPED | SC14421_RAMBANK1
);
to_dip(
sc14421_base + 0x4A,
scan_II_init3,
ARRAY_SIZE(scan_II_init3)
);
to_dip(
sc14421_base + 0x58,
scan_init5,
ARRAY_SIZE(scan_init5)
);
to_dip(
sc14421_base + 0x50,
scan_init4,
ARRAY_SIZE(scan_init4));
/* printk("starting dip\n"); */
SC14421_switch_to_bank(sc14421_base, SC14421_RAMBANK0);
}
void sniffer_init_sniff_sync(struct coa_info *dev)
{
uint16_t *sc14421_base = dev->sc14421_base;
printk("loading sniff_sync firmware\n");
SC14421_switch_to_bank(
sc14421_base,
SC14421_DIPSTOPPED | SC14421_CODEBANK
);
to_dip(
sc14421_base,
sc14421_II_sniff_sync_fw,
ARRAY_SIZE(sc14421_II_sniff_sync_fw));
printk("clear interrupt\n");
SC14421_clear_interrupt(sc14421_base);
SC14421_switch_to_bank(
sc14421_base,
SC14421_DIPSTOPPED | SC14421_RAMBANK0
);
to_dip(
sc14421_base + 0x00,
sync_init1,
ARRAY_SIZE(sync_init1)
);
to_dip(
sc14421_base + 0x10,
sync_init2,
ARRAY_SIZE(sync_init2));
/* set channel */
switch(dev->radio_type)
{
case COA_RADIO_TYPE_II:
sync_II_init3[0] =
(scan_II_init3[0] & 0xC1) |
( (10 - dev->sniffer_config->channel) << 1);
break;
default:
printk("ERROR: this radio type is currently not "
"supported. please update the driver\n");
;
}
sync_init5[0] |= 0x01;
SC14421_switch_to_bank(
sc14421_base,
SC14421_DIPSTOPPED | SC14421_RAMBANK1
);
to_dip(
sc14421_base + 0x4A,
sync_II_init3,
ARRAY_SIZE(sync_II_init3)
);
to_dip(
sc14421_base + 0x58,
sync_init5,
ARRAY_SIZE(sync_init5)
);
to_dip(
sc14421_base + 0x50,
sync_init4,
ARRAY_SIZE(sync_init4)
);
dev->sniffer_config->status = 0;
sniffer_clear_slottable(dev->sniffer_config->slottable);
printk("starting dip\n");
SC14421_switch_to_bank(sc14421_base, SC14421_RAMBANK0);
}
void sniffer_irq_handler(struct coa_info *dev)
{
int irq;
if (dev->sc14421_base)
{
irq = SC14421_clear_interrupt(dev->sc14421_base);
switch(dev->sniffer_config->snifftype)
{
case SNIFF_SCANFP:
case SNIFF_SCANPP:
sniffer_sniff_scan_irq(dev, irq);
break;
case SNIFF_SYNC:
sniffer_sniff_sync_irq(dev, irq);
break;
}
}
}
void sniffer_sniff_scan_irq(struct coa_info *dev, int irq)
{
volatile uint16_t *sc14421_base = dev->sc14421_base;
if (dev->open)
{
SC14421_switch_to_bank(sc14421_base, SC14421_RAMBANK1);
if ( (SC14421_READ(1) & 0xc0) == 0xc0) /* Checksum ok */
{
uint8_t rssi = SC14421_READ(0);
from_dip(
fppacket + 5,
sc14421_base + 6,
6);
SC14421_WRITE(1, 0); /* Clear Checksum-Flag */
if (dect_is_RFPI_Packet(fppacket))
{
int ret;
uint8_t station[7];
station[0] = dev->sniffer_config->channel;
station[1] = rssi;
memcpy(&station[2], &fppacket[6], 5); /* RFPI */
ret = kfifo_put(dev->rx_fifo, station, 7);
if (ret <= 0)
{
printk("com_on_air_cs: rx fifo full? "
"kfifo_put() = %d\n", ret);
}
}
}
}
}
void sniffer_sniff_sync_irq(struct coa_info *dev, int irq)
{
volatile uint16_t *sc14421_base = dev->sc14421_base;
struct sniffer_cfg *config = dev->sniffer_config;
int r;
SC14421_switch_to_bank(sc14421_base, SC14421_RAMBANK1);
if (!(config->status & SNIFF_STATUS_FOUNDSTATION))
{
if (irq & 0x01)
{
#if 0
printk("N:");
for (r=0; r<16; r++)
printk("%.2x ", SC14421_READ(r));
printk("\n");
#endif
if ( (SC14421_READ(1) & 0xc0) == 0xc0) /* Checksum ok */
{
SC14421_WRITE(1, 0); /* clear checksum flag */
from_dip(
fppacket + 5,
sc14421_base + 6,
6);
if (dect_compare_RFPI(fppacket, config->RFPI))
{
printk("found station for sync\n");
config->status |=
SNIFF_STATUS_FOUNDSTATION;
SC14421_switch_to_bank(
sc14421_base,
SC14421_CODEBANK
);
SC14421_write_cmd(
sc14421_base,
sync_label_D4,
BR,
sync_label_D1
);
}
}
}
}
else if (!(config->status & SNIFF_STATUS_INSYNC))
{
if (irq & 0x01)
{
int slot;
int i;
#if 0
printk("S:");
for (i=0; i<16; i++)
printk("%.2x ", SC14421_READ(i));
printk("\n");
#endif
if ( (SC14421_READ(1) & 0xc0) == 0xc0) /* Checksum ok */
{
SC14421_WRITE(1, 0); /* clear checksum flag */
from_dip(
fppacket + 5,
sc14421_base + 6,
48);
slot = dect_get_slot(fppacket);
if (slot != -1)
{
/* printk("station in slot %u\n", slot); */
config->status |= SNIFF_STATUS_INSYNC;
slot %= 12;
if (slot%2)
printk("slot not possible "
"with this firmware\n");
config->slottable[slot].active = 1;
config->slottable[slot].channel =
config->channel;
config->slottable[slot].type =
DECT_SLOTTYPE_CARRIER;
config->slottable[slot].errcnt = 0;
sniffer_sync_patchloop(
dev,
config->slottable,
SNIFF_SLOTPATCH_FP
);
sniffer_sync_patchloop(
dev,
config->slottable,
SNIFF_SLOTPATCH_PP
);
SC14421_switch_to_bank(
sc14421_base,
SC14421_CODEBANK
);
printk("set jump to %u\n",
sync_jumptable[slot]);
SC14421_write_cmd(
sc14421_base,
sync_label_D4,
BR,
sync_jumptable[slot]
);
printk("we are in sync :)\n");
struct sniffed_packet packet;
packet.rssi = SC14421_READ(0x00);
packet.channel = config->channel;
packet.slot = slot;
memcpy(packet.data, fppacket, 53);
int ret;
packet.timestamp =
dev->irq_timestamp;
ret = kfifo_put(
dev->rx_fifo,
(unsigned char*) &packet,
sizeof(struct sniffed_packet));
if (ret <= 0)
printk("com_on_air_cs: rx fifo "
"full? kfifo_put() "
"= %d\n", ret);
}
}
}
}
else
{
int i, a;
if ( (irq & 0x09) == 0x09)
printk("interrupt too slow , lost packets!\n");
if (irq & 0x01)
{
for (a=0; a<12; a++)
{
if (config->slottable[a].active)
{
int memofs;
SC14421_switch_to_bank(
sc14421_base,
sync_banktable[a]);
if ( (a/2) % 2)
memofs = 0x80;
else
memofs = 0x00;
if ( (SC14421_READ(1+memofs) & 0xc0) ==
0xc0) /* Checksum ok */
{
struct sniffed_packet packet;
/* fixing indention / coding style is useless beyond here
* need to talk to krater about where to cut in functions
* - mazzoo */
packet.rssi =
SC14421_READ(memofs);
packet.channel =
config->slottable[a].channel;
packet.slot = a;
memcpy(
packet.data,
fppacket,
5);
from_dip(
&packet.data[5],
sc14421_base+memofs+6,
48);
if (config->slottable[a].type ==
DECT_SLOTTYPE_SCAN)
/* we received data on a scan-slot , channel is incemented before , but we want hear the old channel */
{
packet.channel--;
printk("slot in scanmode\n");
}
if (dect_is_multiframe_number(packet.data)) /* if there was a multiframe number , then this packet was in frame 8 (0) */
{
/* printk("found multiframe number\n"); */
config->framenumber = 1;
}
/* if (dev->open) */
{
int ret;
packet.timestamp = dev->irq_timestamp;
ret = kfifo_put(dev->rx_fifo, (unsigned char*) &packet, sizeof(struct sniffed_packet));
if (ret <= 0)
{
printk("com_on_air_cs: rx fifo full? kfifo_put() = %d\n", ret);
}
}
#if 0
printk("F:");
for (i=0; i<16; i++)
printk("%.2x ", SC14421_READ(i+memofs));
printk(" : %.2x : %x\n", irq, a);
#endif
SC14421_WRITE(1+memofs, 0); /* clear checksum flag */
if (dect_update_slottable(config->slottable, a, packet.data))
{
config->updateppslots = 1;
config->updatefpslots = 1;
/* printk("new slot , must update slots\n"); */
}
}
else
{
if (dect_receive_error(config->slottable, a))
{
config->updateppslots = 1;
config->updatefpslots = 1;
printk("died slot , must update slots\n");
}
}
}
}
if ( (!(irq & 0x08)) && (config->updatefpslots) )
{
/* printk("patching fp slots\n"); */
sniffer_sync_patchloop(dev, config->slottable, SNIFF_SLOTPATCH_FP);
config->updatefpslots = 0;
}
}
if (irq & 0x08)
{
for (a=12; a<24; a++)
{
if (config->slottable[a].active)
{
int memofs;
SC14421_switch_to_bank(sc14421_base, sync_banktable[a]);
if ( (a/2) % 2)
memofs = 0x80;
else
memofs = 0x00;
if ( (SC14421_READ(1+memofs) & 0xc0) == 0xc0) /* Checksum ok */
{
struct sniffed_packet packet;
packet.rssi = SC14421_READ(memofs);
packet.channel = config->slottable[a].channel;
packet.slot = a;
memcpy(packet.data, pppacket, 5);
from_dip(&packet.data[5], sc14421_base+memofs+6, 48);
if (config->slottable[a].type == DECT_SLOTTYPE_SCAN)
{
packet.channel--;
printk("slot in scanmode\n");
}
/* if (dev->open) */
{
int ret;
packet.timestamp = dev->irq_timestamp;
ret = kfifo_put(dev->rx_fifo, (unsigned char*) &packet, sizeof(struct sniffed_packet));
if (ret <= 0)
{
printk("com_on_air_cs: rx fifo full? kfifo_put() = %d\n", ret);
}
}
#if 0
printk("F:");
for (i=0; i<16; i++)
printk("%.2x ", SC14421_READ(i+memofs));
printk(" : %.2x : %x\n", irq, a);
#endif
SC14421_WRITE(1+memofs, 0); /* clear checksum flag */
if (dect_update_slottable(config->slottable, a, packet.data))
{
config->updateppslots = 1;
config->updatefpslots = 1;
/* printk("new slot , must update slots\n"); */
}
}
else
{
if (dect_receive_error(config->slottable, a))
{
config->updateppslots = 1;
config->updatefpslots = 1;
/* printk("died slot , must update slots\n"); */
}
}
}
}
if ( (!(irq & 0x01)) && (config->updateppslots) )
{
/* printk("patching pp slots\n"); */
sniffer_sync_patchloop(dev, config->slottable, SNIFF_SLOTPATCH_PP);
config->updateppslots = 0;
}
if (dect_update_scanchannels(config->slottable))
{
config->updateppslots = 1;
config->updatefpslots = 1;
/* printk("new slot , must update slots\n"); */
}
if (config->framenumber >= 7)
config->framenumber = 0;
else
config->framenumber++;
}
}
}
void sniffer_sync_patchloop(struct coa_info *dev, struct dect_slot_info *slottable, int type)
{
int slot, offset = 0;
volatile uint16_t *sc14421_base = dev->sc14421_base;
struct sniffer_cfg *config = dev->sniffer_config;
if (type == SNIFF_SLOTPATCH_PP)
offset = 12;
for (slot = offset; slot < (offset+12); slot++)
{
if (slottable[slot].update)
{
slottable[slot].update = 0;
if (slottable[slot].active && (slot%2))
{
static int fixme_count = 23;
if (fixme_count)
{
fixme_count--;
printk("can't use slot %u with this firmware !\n", slot);
}
continue;
}
if (slottable[slot].active)
{
int memofs;
/* set channel */
switch(dev->radio_type)
{
case COA_RADIO_TYPE_II:
sync_II_init3[0] = (sync_II_init3[0] & 0xC1) | ((10-slottable[slot].channel) << 1);
break;
default:
printk("ERROR: this radio type is currently not supported. please update the driver\n");
}
if (slot > 11)
sync_init5[0] &= 0xFE;
else
sync_init5[0] |= 0x01;
if ( (slot/2) % 2)
memofs = 0x80;
else
memofs = 0x00;
sync_init5[6] = config->framenumber%8;
SC14421_switch_to_bank(sc14421_base, sync_banktable[slot]);
to_dip(sc14421_base + 0x4A + memofs, sync_II_init3, ARRAY_SIZE(sync_II_init3));
to_dip(sc14421_base + 0x58 + memofs, sync_init5, ARRAY_SIZE(sync_init5));
to_dip(sc14421_base + 0x50 + memofs, sync_init4, ARRAY_SIZE(sync_init4));
/* printk("patching slot %u at addr %u\n", slot, sync_patchtable[slot]); */
SC14421_switch_to_bank(sc14421_base, SC14421_CODEBANK);
SC14421_write_cmd(sc14421_base, sync_patchtable[slot], JMP, sync_label_28);
}
else
{
SC14421_switch_to_bank(sc14421_base, SC14421_CODEBANK);
SC14421_write_cmd(sc14421_base, sync_patchtable[slot], WNT, 2);
/* printk("patching addr %u for wait\n", sync_patchtable[slot]); */
}
}
else if (slottable[slot].active && (slottable[slot].type == DECT_SLOTTYPE_CARRIER))
{
SC14421_switch_to_bank(sc14421_base, sync_banktable[slot]);
SC14421_WRITE(0x5e, config->framenumber%8);
}
}
}
void sniffer_clear_slottable(struct dect_slot_info *slottable)
{
int i;
for (i=0; i<24; i++)
{
slottable[i].active = 0;
slottable[i].update = 1;
}
}

View File

@ -0,0 +1,75 @@
/*
* com_on_air_cs - basic driver for the Dosch and Amand "com on air" cards
*
* 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.
*
* authors:
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
*
*/
#ifndef SC14421_SNIFF_H
#define SC14421_SNIFF_H
#include "com_on_air_user.h"
#define SNIFF_SCANFP COA_SUBMODE_SNIFF_SCANFP
#define SNIFF_SCANPP COA_SUBMODE_SNIFF_SCANPP
#define SNIFF_SYNC COA_SUBMODE_SNIFF_SYNC
#define SNIFF_STATUS_FOUNDSTATION 0x80
#define SNIFF_STATUS_INSYNC 0x40
#define SNIFF_SLOTPATCH_FP 0
#define SNIFF_SLOTPATCH_PP 1
#include "dect.h"
#include "com_on_air.h"
struct sniffer_cfg
{
int snifftype;
int channel;
unsigned char RFPI[5];
unsigned char status;
struct dect_slot_info slottable[24];
int framenumber;
int updatefpslots;
int updateppslots;
};
struct sniffed_rfpi
{
unsigned char rssi;
unsigned char channel;
unsigned char RFPI[5];
};
#define SLOT_OUT_OF_SYNC 0x20
#define SLOT_IN_SYNC 0x21
struct sniffed_packet
{
unsigned char rssi;
unsigned char channel;
unsigned char slot;
struct timespec timestamp;
unsigned char data[53];
};
void sniffer_init(struct coa_info *dev);
void sniffer_init_sniff_all(struct coa_info *dev);
void sniffer_init_sniff_scan(struct coa_info *dev);
void sniffer_init_sniff_sync(struct coa_info *dev);
void sniffer_irq_handler(struct coa_info *dev);
void sniffer_sniff_all_irq(struct coa_info *dev,int irq);
void sniffer_sniff_scan_irq(struct coa_info *dev,int irq);
void sniffer_sniff_sync_irq(struct coa_info *dev,int irq);
void sniffer_sync_patchloop(struct coa_info *dev,struct dect_slot_info *slottable,int type);
void sniffer_clear_slottable(struct dect_slot_info *slottable);
#endif

View File

@ -0,0 +1,9 @@
CFLAGS=-Wall -O2 -I..
PROGS=coa_syncsniff pcap2cchan
PCAP_PROGS=pcapstein dect_cli
all:$(PROGS) $(PCAP_PROGS)
$(PCAP_PROGS): $(foreach p,$(PCAP_PROGS), $p.c)
$(CC) $(CFLAGS) -lpcap $@.c -o $@
clean:
rm -f $(PROGS) $(PCAP_PROGS)

View File

@ -0,0 +1,199 @@
/*
* coa_syncsniff dumps pcap files on a given channel and RFPI
*
* 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.
*
* authors:
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
*
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/socket.h>
#include <net/ethernet.h>
#include <arpa/inet.h>
#include <netinet/ether.h>
#include "com_on_air_user.h"
struct sniffed_packet
{
unsigned char rssi;
unsigned char channel;
unsigned char slot;
struct timespec timestamp;
unsigned char data[53];
};
struct pcap_global_header
{
uint32_t magic_number; /* magic number */
uint16_t version_major; /* major version number */
uint16_t version_minor; /* minor version number */
int thiszone; /* GMT to local correction */
uint32_t sigfigs; /* accuracy of timestamps */
uint32_t snaplen; /* max length of captured packets, in octets */
uint32_t network; /* data link type */
};
struct pcap_record_header
{
uint32_t ts_sec; /* timestamp seconds */
uint32_t ts_usec; /* timestamp microseconds */
uint32_t incl_len; /* number of octets of packet saved in file */
uint32_t orig_len; /* actual length of packet */
};
void write_global_header(FILE *pcap);
void write_record(FILE *pcap,uint32_t sec,uint32_t usec,uint32_t len,unsigned char *record);
#define DEV "/dev/coa"
/* we use some "hidden" ioctls */
#define COA_IOCTL_TEST0 0xF000
#define COA_IOCTL_TEST1 0xF001
#define COA_IOCTL_TEST2 0xF002
#define COA_IOCTL_TEST3 0xF003
#define COA_IOCTL_TEST4 0xF004
#define COA_IOCTL_TEST5 0xF005
#define COA_IOCTL_TEST6 0xF006
#define COA_IOCTL_TEST7 0xF007
#define COA_IOCTL_DUMP_DIP_RAM COA_IOCTL_TEST0
#define COA_IOCTL_FIFO_TEST COA_IOCTL_TEST1
#define COA_IOCTL_COUNT_IRQ COA_IOCTL_TEST2
/* default RFPI */
uint8_t RFPI[5]={0x00,0x00,0x00,0x00,0x00};
int main(int argc, char *argv[])
{
int d;
int ret = 0;
FILE *pcap;
if(argc<2)
{
printf( "Usage:coa_syncsniff channel pcap-file [RFPI]\n");
exit(-1);
}
d=open(DEV, O_RDONLY);
if (d<0)
{
printf("couldn't open(\"%s\"): %s\n", DEV, strerror(errno));
exit(1);
}
pcap=fopen(argv[2],"wb");
if(!pcap)
{
printf("Cant open pcap file for write...\n");
exit(1);
}
/* optionally accept RFPI as 3rd argument on commandline */
if(argc>2)
{
sscanf(argv[3], "%hhx %hhx %hhx %hhx %hhx", &RFPI[0], &RFPI[1], &RFPI[2], &RFPI[3], &RFPI[4]);
printf("RFPI: %02x %02x %02x %02x %02x\n", RFPI[0], RFPI[1], RFPI[2], RFPI[3], RFPI[4]);
}
//set sync sniff mode
uint16_t val;
val = COA_MODE_SNIFF|COA_SUBMODE_SNIFF_SYNC;
if(ioctl(d,COA_IOCTL_MODE, &val)){printf("couldn't ioctl()\n");exit(1);}
//set rfpi to sync with
if(ioctl(d,COA_IOCTL_SETRFPI, RFPI)){printf("couldn't ioctl()\n");exit(1);}
//set channel
uint32_t chn=atoi(argv[1]);
printf("set channel %u\n",chn);
if(ioctl(d,COA_IOCTL_CHAN,&chn)){printf("couldn't set channel\n");exit(1);}
write_global_header(pcap);
//sniff-loop
while (0xDEC + 't')
{
struct sniffed_packet buf;
while (sizeof(struct sniffed_packet) == (ret = read(d, &buf, (sizeof(struct sniffed_packet)))))
{
unsigned char packet[100];
packet[12]=0x23;
packet[13]=0x23;
packet[14]=0x00; //decttype (receive)
packet[15]=buf.channel; //channel
packet[16]=0;
packet[17]=buf.slot; //slot
packet[18]=0;
packet[19]=buf.rssi;
memcpy(packet+20,buf.data,53);
write_record(
pcap,
buf.timestamp.tv_sec,
buf.timestamp.tv_nsec/1000,
73,
packet);
}
}
return ret;
}
void write_global_header(FILE *pcap)
{
struct pcap_global_header header;
header.magic_number=0xa1b2c3d4;
header.version_major=2;
header.version_minor=4;
header.thiszone=0;//GMT
header.sigfigs=0;
header.snaplen=1024;
header.network=1;
fwrite(&header,1,sizeof(struct pcap_global_header),pcap);
}
void write_record(FILE *pcap,uint32_t sec,uint32_t usec,uint32_t len,unsigned char *record)
{
struct pcap_record_header header;
header.ts_sec=sec;
header.ts_usec=usec;
header.incl_len=len;
header.orig_len=len;
fwrite(&header,1,sizeof(struct pcap_record_header),pcap);
fwrite(record,1,len,pcap);
}

View File

@ -0,0 +1,158 @@
/*
* DECT C channel definitions
*
* 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.
*
* authors:
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
*
*/
#ifndef DECT_CCHAN_H
#define DECT_CCHAN_H
struct strtype
{
char type;
char name[100];
};
struct strtype msgtype[16]=
{
{0,"0000 LCE (Link Control Entity) messages"},
{1,""},
{2,""},
{3,"0011 CC (Call Control) messages"},
{4,"0100 CISS (Call Independent Supplementary Services) messages"},
{5,"0101 MM (Mobility Management) messages"},
{6,"0110 CLMS (ConnectionLess Message Service) messages"},
{7,"0111 COMS (Connection Oriented Message Service) messages"}
};
struct strtype cctype[256]=
{
{0x01,"{CC-ALERTING}"},
{0x02,"{CC-CALL-PROC}"},
{0x05,"{CC-SETUP}"},
{0x07,"{CC-CONNECT}"},
{0x0d,"{CC-SETUP-ACK}"},
{0x0f,"{CC-CONNECT-ACK}"},
{0x20,"{CC-SERVICE-CHANGE}"},
{0x21,"{CC-SERVICE-ACCEPT}"},
{0x23,"{CC-SERVICE-REJECT}"},
{0x4d,"{CC-RELEASE}"},
{0x5a,"{CC-RELEASE-COM}"},
{0x60,"{IWU-INFO}"},
{0x6e,"{CC-NOTIFY}"},
{0x7b,"{CC-INFO}"}
};
struct strtype mmtype[256]=
{
{0x40,"{AUTHENTICATION-REQUEST}"},
{0x41,"{AUTHENTICATION-REPLY}"},
{0x42,"{KEY-ALLOCATE}"},
{0x43,"{AUTHENTICATION-REJECT}"},
{0x44,"{ACCESS-RIGHTS-REQUEST}"},
{0x45,"{ACCESS-RIGHTS-ACCEPT}"},
{0x47,"{ACCESS-RIGHTS-REJECT}"},
{0x48,"{ACCESS-RIGHTS-TERMINATE-REQUEST}"},
{0x49,"{ACCESS-RIGHTS-TERMINATE-ACCEPT}"},
{0x4b,"{ACCESS-RIGHTS-TERMINATE-REJECT}"},
{0x4c,"{CIPHER-REQUEST}"},
{0x4e,"{CIPHER-SUGGEST}"},
{0x4f,"{CIPHER-REJECT}"},
{0x50,"{MM-INFO-REQUEST}"},
{0x51,"{MM-INFO-ACCEPT}"},
{0x52,"{MM-INFO-SUGGEST}"},
{0x53,"{MM-INFO-REJECT}"},
{0x54,"{LOCATE-REQUEST}"},
{0x55,"{LOCATE-ACCEPT}"},
{0x56,"{DETACH}"},
{0x57,"{LOCATE-REJECT}"},
{0x58,"{IDENTITY-REQUEST}"},
{0x5a,"{IDENTITY-REPLY}"},
{0x5b,"{MM-IWU}"},
{0x5c,"{TEMPORARY-IDENTITY-ASSIGN}"},
{0x5d,"{TEMPORARY-IDENTITY-ASSIGN-ACK}"},
{0x5f,"{TEMPORARY-IDENTITY-ASSIGN-REJ}"},
{0x6e,"{MM-NOTIFY}"}
};
struct strtype sstype[256]=
{
{0x24,"{HOLD}"},
{0x28,"{HOLD-ACK}"},
{0x30,"{HOLD-REJECT}"},
{0x31,"{RETRIEVE}"},
{0x33,"{RETRIEVE-ACK}"},
{0x37,"{RETRIEVE-REJECT}"},
{0x5a,"{CISS-RELEASE-COM}"},
{0x62,"{FACILITY}"},
{0x64,"{CISS-REGISTER}"},
};
struct cfrag
{
int valid;
int slot;
char cttype;
unsigned char data[5];
};
struct cpacket
{
int valid;
unsigned char addr;
unsigned char ctrl;
unsigned char length;
unsigned char data[80];
unsigned short checksum;
};
struct cdevice
{
char type;
int found;
char cnt;
int cdata;
struct cpacket packet;
};
char lenlookup[64]={
5,10,10,10,10,10,15,15,
15,15,15,20,20,20,20,20,
25,25,25,25,25,30,30,30,
30,30,35,35,35,35,35,40,
40,40,40,40,45,45,45,45,
45,50,50,50,50,50,55,55,
55,55,55,60,60,60,60,60,
65,65,65,65,65,70,70,70
};
char pklookup[64]={
1,2,2,2,2,2,3,3,
3,3,3,4,4,4,4,4,
5,5,5,5,5,6,6,6,
6,6,7,7,7,7,7,8,
8,8,8,8,9,9,9,9,
9,10,10,10,10,10,11,11,
11,11,11,12,12,12,12,12,
13,13,13,13,13,14,14,14
};
struct cfrag getcfrag(unsigned char *dect,int slot);
struct cpacket getcpacket(struct cfrag frag,struct cdevice *device);
void printcpacket(struct cpacket packet,char *prefix);
char *getstring(struct strtype *str,int id,int max);
#endif

View File

@ -0,0 +1,671 @@
/*
* dect_cli async and sync interface to DECT, can dump pcap files
*
* 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.
*
* authors:
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <time.h>
#include <limits.h>
#include <pcap.h>
#include "com_on_air_user.h"
#include "dect_cli.h"
//#define DUMP_IRQ_COUNT_ONCE_PER_SEC
struct cli_info cli;
#define RXBUF 8192
char buf[RXBUF];
/* pcap errors */
char errbuf[PCAP_ERRBUF_SIZE];
void print_help(void)
{
LOG("\n");
LOG(" help - this help\n");
LOG(" fpscan - async scan for basestations, dump RFPIs\n");
LOG(" callscan - async scan for active calls, dump RFPIs\n");
LOG(" autorec - sync on any calls in callscan, autodump in pcap, currently %s\n", cli.autorec ? "ON":"OFF");
LOG(" ppscan <rfpi> - sync scan for active calls\n");
LOG(" chan <ch> - set current channel [0-9], currently %d\n", cli.channel);
// LOG(" slot <sl> - set current slot [0-23], currently %d\n", cli.slot);
// LOG(" jam - jam current channel\n");
LOG(" dump - dump stations and calls we have seen\n");
LOG(" hop - toggle channel hopping, currently %s\n", cli.hop ? "ON":"OFF");
LOG(" verb - toggle verbosity, currently %s\n", cli.verbose ? "ON":"OFF");
LOG(" stop - stop it - whatever we were doing\n");
LOG(" quit - well :)\n");
LOG("\n");
}
void set_channel(uint32_t channel)
{
if (cli.verbose)
LOG("### switching to channel %d\n", channel);
if (ioctl(cli.fd, COA_IOCTL_CHAN, &channel)){
LOG("!!! couldn't ioctl()\n");
exit(1);
}
cli.last_hop = time(NULL);
}
void set_slot(uint32_t slot)
{
LOG("!!! not yet implemented :(\n");
}
void do_ppscan(uint8_t * RFPI)
{
LOG("### trying to sync on %.2x %.2x %.2x %.2x %.2x\n",
RFPI[0],
RFPI[1],
RFPI[2],
RFPI[3],
RFPI[4]
);
/* set sync sniff mode */
uint16_t val;
val = COA_MODE_SNIFF | COA_SUBMODE_SNIFF_SYNC;
if (ioctl(cli.fd, COA_IOCTL_MODE, &val)){
LOG("!!! couldn't ioctl()\n");
exit(1);
}
/* set rfpi to sync with */
if(ioctl(cli.fd, COA_IOCTL_SETRFPI, RFPI)){
LOG("!!! couldn't ioctl()\n");
exit(1);
}
set_channel(cli.channel);
memcpy(cli.RFPI, RFPI, 5);
cli.mode = MODE_PPSCAN;
cli.autorec_last_bfield = time(NULL);
}
void add_station(struct dect_station * station)
{
int i;
LOG("### found new %s", station->type == TYPE_FP ? "station":"call on");
for (i=0; i<5; i++)
LOG(" %.2x", station->RFPI[i]);
LOG(" on channel %d RSSI %d\n", station->channel, station->RSSI);
struct dect_station * p = cli.station_list;
if (p)
{ /* append to existing list */
while (p->next)
p = p->next;
p->next = malloc(sizeof(*p));
p = p->next;
}else /* create 1st element in list */
{
cli.station_list = malloc(sizeof(*cli.station_list));
p = cli.station_list;
}
if (!p)
{
LOG("!!! out of memory\n");
exit(1);
}
memset(p, 0, sizeof(*p));
memcpy(p->RFPI, station->RFPI, 5);
p->channel = station->channel;
p->RSSI = station->RSSI;
p->type = station->type;
p->first_seen = time(NULL);
p->last_seen = p->first_seen;
p->count_seen = 1;
if (cli.autorec)
do_ppscan(station->RFPI);
}
void try_add_station(struct dect_station * station)
{
struct dect_station * p = cli.station_list;
int found = 0;
while (p)
{
if (!memcmp(p->RFPI, station->RFPI, 5))
{
if (p->type == station->type)
{
if ( (p->channel != station->channel) &&
(cli.verbose) )
{
int i;
LOG("### station");
for (i=0; i<5; i++)
LOG(" %.2x", station->RFPI[i]);
LOG(" switched from channel %d to channel %d\n",
p->channel,
station->channel);
}
found = 1;
p->channel = station->channel;
p->count_seen++;
p->last_seen = time(NULL);
p->RSSI += station->RSSI; /* we avg on dump */
}
}
p = p->next;
}
if (!found)
add_station(station);
}
void do_fpscan(void)
{
LOG("### starting fpscan\n");
uint16_t val;
val = COA_MODE_SNIFF | COA_SUBMODE_SNIFF_SCANFP;
if (ioctl(cli.fd, COA_IOCTL_MODE, &val)){
LOG("!!! couldn't ioctl()\n");
exit(1);
}
/* set start channel */
set_channel(cli.channel);
cli.mode = MODE_FPSCAN;
cli.autorec = 0;
}
void do_callscan(void)
{
LOG("### starting callscan\n");
uint16_t val;
val = COA_MODE_SNIFF | COA_SUBMODE_SNIFF_SCANPP;
if (ioctl(cli.fd, COA_IOCTL_MODE, &val)){
LOG("!!! couldn't ioctl()\n");
exit(1);
}
/* set start channel */
set_channel(cli.channel);
cli.mode = MODE_CALLSCAN;
}
void do_ppscan_str(char * str_rfpi)
{
uint8_t RFPI[5];
char * end;
int i;
for (i=0; i<5; i++)
{
RFPI[i] = strtoul(str_rfpi, &end, 16);
if ((errno == ERANGE )
|| (errno != 0 && RFPI[i] == 0))
{
LOG("!!! please enter a valid RFPI (e.g. 00 01 02 03 04)\n");
return;
}
if (end == str_rfpi)
{
LOG("!!! please enter a valid RFPI (e.g. 00 01 02 03 04)\n");
return;
}
str_rfpi = end;
}
do_ppscan(RFPI);
}
void do_chan(char * str_chan)
{
uint32_t channel;
char * end;
channel = strtoul(str_chan, &end, 0);
if ((errno == ERANGE && (channel == LONG_MAX || channel == LONG_MIN))
|| (errno != 0 && channel == 0))
{
LOG("!!! please enter a valid channel number [0-9]\n");
return;
}
if (end == str_chan)
{
LOG("!!! please enter a valid channel number [0-9]\n");
return;
}
if (channel > 9)
{
LOG("!!! please enter a valid channel number [0-9]\n");
return;
}
cli.channel = channel;
set_channel(cli.channel);
}
void do_slot(char * str_chan)
{
uint32_t slot;
char * end;
slot = strtoul(str_chan, &end, 0);
if ((errno == ERANGE && (slot == LONG_MAX || slot == LONG_MIN))
|| (errno != 0 && slot == 0))
{
LOG("!!! please enter a valid slot number [0-23]\n");
return;
}
if (end == str_chan)
{
LOG("!!! please enter a valid slot number [0-23]\n");
return;
}
if (slot > 23)
{
LOG("!!! please enter a valid slot number [0-23]\n");
return;
}
cli.slot = slot;
set_slot(cli.slot);
}
void do_jam(void)
{
LOG("!!! not yet implemented :(\n");
}
void do_dump(void)
{
int i;
struct dect_station * p = cli.station_list;
if (!p)
{
LOG("### nothing found so far\n");
return;
}
LOG("### stations\n");
do
{
if (p->type == TYPE_FP)
{
LOG(" ");
for (i=0; i<5; i++)
LOG(" %.2x", p->RFPI[i]);
LOG(" ch %1.1d ", p->channel);
LOG(" RSSI %5.2f ", (double)p->RSSI / p->count_seen);
LOG(" count %4.u ", p->count_seen);
LOG(" first %u ", p->first_seen);
LOG(" last %u ", p->last_seen);
LOG("\n");
}
} while ((p = p->next));
p = cli.station_list;
LOG("### calls\n");
do
{
if (p->type == TYPE_PP)
{
LOG(" ");
for (i=0; i<5; i++)
LOG(" %.2x", p->RFPI[i]);
LOG(" ch %1.1d ", p->channel);
LOG(" RSSI %5.2f ", (double)p->RSSI / p->count_seen);
LOG(" count %4.u ", p->count_seen);
LOG(" first %u ", p->first_seen);
LOG(" last %u ", p->last_seen);
LOG("\n");
}
} while ((p = p->next));
}
void do_hop(void)
{
cli.hop = cli.hop ? 0:1;
LOG("### channel hopping turned %s\n", cli.hop ? "ON":"OFF");
}
void do_verb(void)
{
cli.verbose = cli.verbose ? 0:1;
LOG("### verbosity turned %s\n", cli.verbose ? "ON":"OFF");
}
void do_autorec(void)
{
cli.autorec = cli.autorec ? 0:1;
LOG("### autorec turned %s\n", cli.autorec ? "ON":"OFF");
}
void do_stop(void)
{
if (!(cli.mode & MODE_STOP))
{
LOG("### stopping DIP\n");
uint16_t val;
val = COA_MODE_IDLE;
if (ioctl(cli.fd, COA_IOCTL_MODE, &val)){
LOG("couldn't ioctl()\n");
exit(1);
}
cli.mode = MODE_STOP;
cli.autorec = 0;
}
}
void process_cli_data()
{
int ret;
ret = read(cli.in, buf, RXBUF);
buf[ret]=0;
if(buf[ret-1] == '\n')
buf[ret-1] = 0;
int done = 0;
if ( !strncasecmp((char *)buf, "help", 4) )
{ print_help(); done = 1; }
if ( !strncasecmp((char *)buf, "fpscan", 6) )
{ do_fpscan(); done = 1; }
if ( !strncasecmp((char *)buf, "callscan", 8) )
{ do_callscan(); done = 1; }
if ( !strncasecmp((char *)buf, "autorec", 7) )
{ do_autorec(); done = 1; }
if ( !strncasecmp((char *)buf, "ppscan", 6) )
{ do_ppscan_str(&buf[6]); done = 1; }
if ( !strncasecmp((char *)buf, "chan", 4) )
{ do_chan(&buf[4]); done = 1; }
if ( !strncasecmp((char *)buf, "slot", 4) )
{ do_slot(&buf[4]); done = 1; }
if ( !strncasecmp((char *)buf, "jam", 3) )
{ do_jam(); done = 1; }
if ( !strncasecmp((char *)buf, "dump", 4) )
{ do_dump(); done = 1; }
if ( !strncasecmp((char *)buf, "hop", 3) )
{ do_hop(); done = 1; }
if ( !strncasecmp((char *)buf, "verb", 4) )
{ do_verb(); done = 1; }
if ( !strncasecmp((char *)buf, "stop", 4) )
{ do_stop(); done = 1; }
if ( !strncasecmp((char *)buf, "quit", 4) )
{ do_stop(); exit(0); }
if(!done)
LOG("!!! no such command %s\n", buf);
}
void init_pcap(struct sniffed_packet * packet)
{
char fname[100];
sprintf(fname, "dump_%.2x_%.2x_%.2x_%.2x_%.2x.pcap",
cli.RFPI[0],
cli.RFPI[1],
cli.RFPI[2],
cli.RFPI[3],
cli.RFPI[4]);
LOG("### dumping to %s\n", fname);
cli.pcap = pcap_open_dead(DLT_EN10MB, 73);
if (!cli.pcap)
{
LOG("!!! couldn't pcap_open_dead(\"%s\")\n", fname);
}
cli.pcap_d = pcap_dump_open(cli.pcap, fname);
if (!cli.pcap_d)
{
LOG("!!! couldn't pcap_dump_open(\"%s\")\n", fname);
}
}
int has_b_field()
{
if ((cli.packet.data[0x19] & 0x0e) != 0x0e)
return 1;
return 0;
}
void process_dect_data()
{
int ret;
switch (cli.mode)
{
case MODE_FPSCAN:
while (7 == (ret = read(cli.fd, buf, 7))){
memcpy(cli.station.RFPI, &buf[2], 5);
cli.station.channel = buf[0];
cli.station.RSSI = buf[1];
cli.station.type = TYPE_FP;
try_add_station(&cli.station);
}
break;
case MODE_CALLSCAN:
while (7 == (ret = read(cli.fd, buf, 7))){
memcpy(cli.station.RFPI, &buf[2], 5);
cli.station.channel = buf[0];
cli.station.RSSI = buf[1];
cli.station.type = TYPE_PP;
try_add_station(&cli.station);
}
break;
case MODE_PPSCAN:
while ( sizeof(cli.packet) ==
read(cli.fd, &cli.packet, sizeof(cli.packet)))
{
if (!cli.pcap)
{
LOG("### got sync\n");
init_pcap(&cli.packet);
/* this is not actually a B-Field,
* but we expect some to come soon
* and the val needs to be non-0 */
cli.autorec_last_bfield = time(NULL);
}
if (has_b_field())
cli.autorec_last_bfield = time(NULL);
struct pcap_pkthdr pcap_hdr;
pcap_hdr.caplen = 73;
pcap_hdr.len = 73;
ret = gettimeofday(&pcap_hdr.ts, NULL);
if (ret)
{
LOG("!!! couldn't gettimeofday(): %s\n",
strerror(errno));
exit(1);
}
uint8_t pcap_packet[100];
memset(pcap_packet, 0, 100);
pcap_packet[12] = 0x23;
pcap_packet[13] = 0x23;
pcap_packet[14] = 0x00; /* decttype (receive) */
pcap_packet[15] = cli.packet.channel;
pcap_packet[16] = 0;
pcap_packet[17] = cli.packet.slot;
pcap_packet[18] = 0;
pcap_packet[19] = cli.packet.rssi;
memcpy(&pcap_packet[20], cli.packet.data, 53);
pcap_dump(cli.pcap_d, &pcap_hdr, pcap_packet);
}
break;
}
}
void init_dect()
{
cli.fd = open(DEV, O_RDWR | O_NONBLOCK);
if (cli.fd < 0)
{
LOG("!!! couldn't open(\"%s\"): %s\n",
DEV,
strerror(errno));
exit(1);
}
cli.pcap = NULL;
}
void init_cli()
{
cli.channel = 0;
cli.slot = 0;
cli.hop = 1;
cli.hop_ch_time = 1; /* in sec */
cli.mode = MODE_STOP;
cli.in = fileno(stdin);
cli.verbose = 0;
cli.station_list = NULL;
cli.autorec = 0;
cli.autorec_timeout = 10;
cli.autorec_last_bfield = 0;
}
void init(void)
{
init_dect();
init_cli();
}
int max_int(int a, int b)
{
if (a>b)
return a;
else
return b;
}
void mainloop(void)
{
fd_set rfd;
fd_set wfd;
fd_set efd;
int nfds = max_int(cli.in, cli.fd);
nfds++;
struct timeval tv;
int ret;
#ifdef DUMP_IRQ_COUNT_ONCE_PER_SEC
#define COA_IOCTL_COUNT_IRQ 0xF002
uint32_t lasttime = time(NULL);
#endif
while (0xDEC + 'T')
{
tv.tv_sec = 1;
tv.tv_usec = 0;
FD_ZERO(&rfd);
FD_ZERO(&wfd);
FD_ZERO(&efd);
FD_SET(cli.in, &rfd);
FD_SET(cli.fd, &rfd);
FD_SET(cli.in, &efd);
FD_SET(cli.fd, &efd);
ret = select(nfds, &rfd, &wfd, &efd, &tv);
if (ret < 0)
{
LOG("!!! select()\n");
exit(1);
}
if (FD_ISSET(cli.in, &efd))
{
LOG("!!! select() on in: %s\n",
strerror(errno));
exit(1);
}
if (FD_ISSET(cli.fd, &efd))
{
LOG("!!! select() on fd: %s\n",
strerror(errno));
exit(1);
}
if (FD_ISSET(cli.in, &rfd))
process_cli_data();
if (FD_ISSET(cli.fd, &rfd))
process_dect_data();
#ifdef DUMP_IRQ_COUNT_ONCE_PER_SEC
if (!(cli.mode & MODE_STOP))
if (time(NULL) >= lasttime + 1)
{
if (ioctl(cli.fd, COA_IOCTL_COUNT_IRQ, NULL))
{
printf("couldn't ioctl()\n");
exit(1);
}
lasttime = time(NULL);
}
#endif
if( (cli.hop) &&
( (cli.mode & MODE_FPSCAN) ||
(cli.mode & MODE_CALLSCAN) ||
(cli.mode & MODE_JAM ) ))
{
if ( time(NULL) > cli.last_hop + cli.hop_ch_time )
{
cli.channel++;
cli.channel %= 10;
set_channel(cli.channel);
}
}
if (cli.autorec)
{
if ( (time (NULL) - cli.autorec_last_bfield
> cli.autorec_timeout)
&&
(cli.mode != MODE_CALLSCAN)
)
{
do_stop();
do_callscan();
if (cli.pcap)
{
pcap_dump_close(cli.pcap_d);
pcap_close(cli.pcap);
cli.pcap_d = NULL;
cli.pcap = NULL;
}
}
}
}
}
int main(int argc, char ** argv)
{
init();
/* make stdout unbuffered */
setvbuf(stdout,(char*)NULL,_IONBF,0);
printf("DECT command line interface\n");
printf("type \"help\" if you're lost\n");
mainloop();
return 0;
}

View File

@ -0,0 +1,85 @@
/*
* dect_cli async and sync interface to DECT, can dump pcap files
*
* 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.
*
* authors:
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
*
*/
#ifndef DECT_CLI_H
#define DECT_CLI_H
#define DEV "/dev/coa"
// too verbose #define LOG(fmt, args...) printf("%s(): " fmt, __FUNCTION__, ##args)
#define LOG(fmt, args...) printf(fmt, ##args)
#define TYPE_FP 23
#define TYPE_PP 42
struct dect_station
{
struct dect_station * next;
uint8_t RFPI[5];
uint32_t RSSI;
uint8_t channel;
uint8_t type;
uint32_t first_seen;
uint32_t last_seen;
uint32_t count_seen;
};
struct sniffed_packet
{
unsigned char rssi;
unsigned char channel;
unsigned char slot;
struct timespec timestamp;
unsigned char data[53];
};
#define MODE_STOP 0x00000001
#define MODE_FPSCAN 0x00000002
#define MODE_PPSCAN 0x00000004
#define MODE_CALLSCAN 0x00000008
#define MODE_JAM 0x00000010
struct cli_info
{
uint8_t RFPI[5];
uint32_t channel;
uint32_t slot;
int hop;
int hop_ch_time; /* in sec */
uint32_t last_hop;
uint32_t mode;
int in; /* stdin */
int fd; /* filehandle to the DECT-trx */
int verbose;
int autorec;
int autorec_timeout;
int autorec_last_bfield;
/* fpscan (async) list of stations */
struct dect_station station;
struct dect_station * station_list;
/* ppscan (sync) */
struct sniffed_packet packet;
pcap_t * pcap;
pcap_dumper_t * pcap_d;
};
#endif /* DECT_CLI_H */

View File

@ -0,0 +1,6 @@
CPPFLAGS=-Wall -O2 -I../.. -lcurses -lpthread
dectshark: dectshark.o gui.o foundinfo.o
g++ $(CPPFLAGS) dectshark.cpp gui.cpp foundinfo.cpp -o dectshark
clean:
rm *.o dectshark

View File

@ -0,0 +1,122 @@
#include <ncurses.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "com_on_air_user.h"
#include "foundinfo.h"
#include "gui.h"
#define DEV "/dev/coa"
void *pcap_threadmain(void *threadid);
void *show_threadmain(void *threadid);
found_dects founds;
print_gui gui;
pthread_t pcap_thread;
pthread_t show_thread;
void set_channel(int dev,int channel);
int main(int argc, char *argv[])
{
int ch;
pthread_create(&pcap_thread, NULL, pcap_threadmain, (void *)0);
// pthread_create(&show_thread, NULL, show_threadmain, (void *)0);
// while(1);
gui.work();
return 0;
}
void *pcap_threadmain(void *threadid)
{
int tid;
int chn=0,channeltime=0;
int dev;
dev = open(DEV, O_RDONLY);
if (dev<0){
printf("couldn't open(\"%s\"): %s\n", DEV, strerror(errno));
}
uint16_t val;
val = COA_MODE_SNIFF|COA_SUBMODE_SNIFF_SCANPP;
if (ioctl(dev, COA_IOCTL_MODE, &val)){
printf("couldn't set sniff mode\n");
}
while(0xDEC + 't') // ;)
{
dect_found found;
unsigned char buf[7];
while (7 == (read(dev, buf, 7)))
{
memcpy(found.RFPI,buf+2,5);
found.channel=buf[0];
found.type=DECT_FOUND_FP;
founds.AddDect(found);
}
usleep(100000);
channeltime++;
if(channeltime == 5)
{
chn++;
chn %= 10;
set_channel(dev,chn);
channeltime = 0;
}
}
pthread_exit(NULL);
}
void set_channel(int dev,int channel)
{
if (ioctl(dev, COA_IOCTL_CHAN, &channel)){
printf("couldn't set channel\n");
}
gui.setchannel(channel);
}
void *show_threadmain(void *threadid)
{
gui.work();
pthread_exit(NULL);
}

View File

@ -0,0 +1,97 @@
#include "foundinfo.h"
found_dects::found_dects()
{
pthread_mutex_init(&mutex,NULL);
listlen=0;
list=(dect_listentry*)malloc(0);
}
found_dects::~found_dects()
{
listlen=0;
free(list);
pthread_mutex_destroy(&mutex);
}
void found_dects::AddDect(dect_found found)
{
unsigned int i;
pthread_mutex_lock(&mutex);
for(i=0;i<listlen;i++)
{
if(list[i].channel==found.channel)
{
if(!memcmp(list[i].RFPI,found.RFPI,5))
{
if(found.type==DECT_FOUND_FP)
list[i].fppackets++;
else
list[i].pppackets++;
pthread_mutex_unlock(&mutex);
return;
}
}
}
listlen++;
list=(dect_listentry*)realloc(list,listlen*sizeof(dect_listentry));
memcpy(list[listlen-1].RFPI,found.RFPI,5);
list[listlen-1].channel=found.channel;
pthread_mutex_unlock(&mutex);
}
void found_dects::ClearList()
{
pthread_mutex_lock(&mutex);
list=(dect_listentry*)realloc(list,0);
listlen=0;
pthread_mutex_unlock(&mutex);
}
dect_listentry found_dects::GetListEntry(unsigned int entry)
{
pthread_mutex_lock(&mutex);
if(entry<listlen)
{
dect_listentry temp=list[entry];
temp.valid=true;
pthread_mutex_unlock(&mutex);
return temp;
}
else
{
pthread_mutex_unlock(&mutex);
dect_listentry temp;
temp.valid=false;
return temp;
}
}
int found_dects::GetListLength()
{
int tlen;
pthread_mutex_lock(&mutex);
tlen=listlen;
pthread_mutex_unlock(&mutex);
return tlen;
}

View File

@ -0,0 +1,55 @@
#include <pthread.h>
#include <malloc.h>
#include <string.h>
#if !defined(FOUNDINFO_H)
#define FOUNDINFO_H
#define DECT_FOUND_FP 0
#define DECT_FOUND_PP 1
#define DECT_FOUND_LISTENTRY 2
#define DECT_FOUND_INVALID 0xFFFF
struct dect_found
{
unsigned int type;
unsigned char RFPI[5];
char channel;
};
struct dect_listentry
{
unsigned char RFPI[5];
char channel;
unsigned int fppackets;
unsigned int pppackets;
bool valid;
};
class found_dects
{
public:
found_dects();
~found_dects();
void AddDect(dect_found found);
void ClearList();
dect_listentry GetListEntry(unsigned int entry);
int GetListLength();
protected:
int listlen;
dect_listentry *list;
pthread_mutex_t mutex;
};
#endif

View File

@ -0,0 +1,247 @@
#include "gui.h"
print_gui::print_gui()
{
selected=startpos=displaypos=0;
}
print_gui::~print_gui()
{
endwin();
}
void print_gui::up()
{
pthread_mutex_lock(&mutex);
if(founds.GetListLength()<=(SH-7))
{
if(displaypos>0)
{
displaypos--;
selected--;
}
}
else
{
if(displaypos>0)
{
displaypos--;
selected--;
}
else if(startpos>0)
{
selected--;
startpos--;
}
}
pthread_mutex_unlock(&mutex);
}
void print_gui::down()
{
pthread_mutex_lock(&mutex);
if(founds.GetListLength()<=(SH-7))
{
if(displaypos<(founds.GetListLength()-1))
{
displaypos++;
selected++;
}
}
else
{
if(displaypos<(SH-8))
{
displaypos++;
selected++;
}
else if(startpos<=(founds.GetListLength()-1-(SH-7)))
{
selected++;
startpos++;
}
}
pthread_mutex_unlock(&mutex);
}
int print_gui::getselected()
{
pthread_mutex_lock(&mutex);
return selected;
pthread_mutex_unlock(&mutex);
}
void print_gui::work()
{
InitCurses();
while(1)
{
if(kbhit_wait(300000))
{
int ch=wgetch(mainwin);
switch(ch)
{
case KEY_LEFT:
break;
case KEY_RIGHT:
break;
case KEY_UP:
up();
break;
case KEY_DOWN:
down();
break;
case 'l':
//SetLockMode();
break;
case 'o':
//SetOverviewMode();
break;
}
}
pthread_mutex_lock(&mutex);
PrintFounds(startpos,SH-7,selected);
PrintStatus(startpos,founds.GetListLength(),channel);
pthread_mutex_unlock(&mutex);
}
}
void print_gui::InitCurses()
{
initscr();
start_color();
init_pair(1,COLOR_GREEN,COLOR_BLACK);
init_pair(2,COLOR_YELLOW,COLOR_BLACK);
init_pair(3,COLOR_WHITE,COLOR_BLACK);
init_pair(4,COLOR_RED,COLOR_BLACK);
init_pair(5,COLOR_YELLOW,COLOR_GREEN);
mainwin = newwin(SH-4,SW-20,0,0);
statuswin = newwin(SH,20,0,SW-20);
msgwin = newwin(4,SW-20,SH-4,0);
// cbreak();
noecho();
keypad(mainwin,TRUE);
wbkgdset(mainwin,(COLOR_PAIR(1)|A_BOLD));
wbkgdset(statuswin,(COLOR_PAIR(1)|A_BOLD));
wbkgdset(msgwin,(COLOR_PAIR(1)|A_BOLD));
box(mainwin,0,0);
wattron(mainwin,COLOR_PAIR(3));
mvwprintw(mainwin,1,1,"RFPI");
mvwprintw(mainwin,1,13,"Ch");
mvwprintw(mainwin,1,31,"FP-Pkt");
mvwprintw(mainwin,1,51,"PP-Pkt");
wnoutrefresh(mainwin);
box(statuswin,0,0);
wattron(statuswin,COLOR_PAIR(2));
mvwprintw(statuswin,1,1,"Station Packets:");
mvwprintw(statuswin,4,1,"Phone Packets:");
mvwprintw(statuswin,SH-3,1,"Channel:");
wnoutrefresh(statuswin);
box(msgwin,0,0);
wnoutrefresh(msgwin);
doupdate();
}
void print_gui::RefreshScreen()
{
wnoutrefresh(mainwin);
wnoutrefresh(statuswin);
wnoutrefresh(msgwin);
doupdate();
}
void print_gui::PrintFounds(int start,int num,int selected)
{
int i,y;
y=2;
for(i=start;i<(start+num);i++)
{
if(i==selected)
wattron(mainwin,COLOR_PAIR(5));
else
wattron(mainwin,COLOR_PAIR(2));
dect_listentry entry=founds.GetListEntry(i);
if(entry.valid)
{
mvwprintw(mainwin,y,1,"%.2x%.2x%.2x%.2x%.2x ",entry.RFPI[0],entry.RFPI[1],entry.RFPI[2],entry.RFPI[3],entry.RFPI[4]);
mvwprintw(mainwin,y,13,"%.2i %12u %12u",entry.channel,entry.fppackets,entry.pppackets);
y++;
}
}
wrefresh(mainwin);
}
void print_gui::PrintStatus(unsigned int PP,unsigned int FP,int channel)
{
wattron(statuswin,COLOR_PAIR(3));
mvwprintw(statuswin,2,1,"%17u",FP);
mvwprintw(statuswin,5,1,"%17u",PP);
mvwprintw(statuswin,SH-2,16,"%2u",channel);
wrefresh(statuswin);
}
void print_gui::setchannel(int chn)
{
pthread_mutex_lock(&mutex);
channel=chn;
pthread_mutex_unlock(&mutex);
}
int print_gui::kbhit_wait(int time)
{
struct timeval tv;
fd_set read_fd;
tv.tv_sec=0;
tv.tv_usec=time;
FD_ZERO(&read_fd);
FD_SET(0,&read_fd);
if(select(1,&read_fd,NULL,NULL,&tv)==-1)
return 0;
if(FD_ISSET(0,&read_fd))
return 1;
return 0;
}

View File

@ -0,0 +1,49 @@
#include <ncurses.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/select.h>
#include "foundinfo.h"
#if !defined(GUI_H)
#define GUI_H
#define SW 80
#define SH 25
extern found_dects founds;
class print_gui
{
public:
print_gui();
~print_gui();
void work();
void up();
void down();
int getselected();
void setchannel(int channel);
protected:
void InitCurses();
void RefreshScreen();
void PrintFounds(int start,int num,int selected);
void PrintStatus(unsigned int PP,unsigned int FP,int channel);
int kbhit_wait(int time);
pthread_mutex_t mutex;
int selected,startpos,displaypos;
WINDOW *mainwin;
WINDOW *statuswin;
WINDOW *msgwin;
int channel;
};
#endif

View File

@ -0,0 +1,246 @@
/*
* pcap2cchan dumps C-channel information from pcap files
*
* 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.
*
* authors:
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dect_c_channel.h"
int main(int argc, char* argv[])
{
struct cfrag frag;
struct cpacket cpacket;
struct cdevice phone,station;
phone.type=station.type=0;
phone.cdata=station.cdata=0;
phone.found=station.found=0;
phone.cnt=station.cnt=0;
unsigned char packet[135];
unsigned int length;
FILE *pcap=fopen(argv[1],"rb");
fseek(pcap,0x18,SEEK_SET);
while(!feof(pcap))
{
fseek(pcap,12,SEEK_CUR);
fread(&length,4,1,pcap);
if(length>135)
{
printf("error , packet size too big\n");
exit(-1);
}
fread(packet,length,1,pcap);
frag=getcfrag(packet+23,packet[17]);
if(frag.valid)
{
if(packet[23]==0x16)
{
cpacket=getcpacket(frag,&phone);
//printf("Frag : %u -> %u:%.2x %.2x %.2x %.2x %.2x\n",frag.slot,frag.cttype,frag.data[0],frag.data[1],frag.data[2],frag.data[3],frag.data[4]);
if(cpacket.valid)
{
printcpacket(cpacket,"phone ");
}
}
else if(packet[23]==0xe9)
{
cpacket=getcpacket(frag,&station);
//printf("Frag : %u -> %u:%.2x %.2x %.2x %.2x %.2x\n",frag.slot,frag.cttype,frag.data[0],frag.data[1],frag.data[2],frag.data[3],frag.data[4]);
if(cpacket.valid)
printcpacket(cpacket,"station");
}
}
}
fclose(pcap);
return 0;
}
struct cfrag getcfrag(unsigned char *dect,int slot)
{
struct cfrag frag;
if((dect[2]&0xc0)==0) //Ct tail (?)
{
frag.valid=1;
frag.cttype=(dect[2]&0x20)>>5;
frag.slot=slot;
memcpy(frag.data,dect+3,5);
}
else
frag.valid=0;
return frag;
}
char *getstring(struct strtype *str,int id,int max)
{
int i;
for(i=0;i<max;i++)
{
if(str[i].type==id)
return str[i].name;
}
return NULL;
}
struct cpacket getcpacket(struct cfrag frag,struct cdevice *device)
{
device->packet.valid=0;
if((frag.cttype!=device->type)&&(!device->found))
{
device->packet.addr=frag.data[0];
device->packet.ctrl=frag.data[1];
device->packet.length=frag.data[2];
if((device->packet.length>>2)>0)
{
device->packet.data[0]=frag.data[3];
device->packet.data[1]=frag.data[4];
device->cdata+=2;
device->cnt=1;
device->found=1;
}
else
{
device->packet.checksum=(((unsigned short)(frag.data[3]))<<8)|(frag.data[4]);
device->packet.valid=1;
device->cdata=0;
device->cnt=0;
device->found=0;
}
device->type=!device->type;
}
else if(frag.cttype!=device->type)
{
memcpy(device->packet.data+device->cdata,frag.data,5);
device->cdata+=5;
device->cnt++;
device->type=!device->type;
if(device->cnt>=pklookup[device->packet.length>>2])
{
device->packet.checksum=(((unsigned short)(frag.data[3]))<<8)|(frag.data[4]);
device->packet.valid=1;
device->cdata=0;
device->cnt=0;
device->found=0;
}
}
else
{
//printf("packet loss (?)\n");
device->type=!device->type;
if(device->found)
{
memset(device->packet.data+device->cdata,0xff,5);
device->cdata+=5;
device->cnt++;
if(device->cnt>=pklookup[device->packet.length>>2])
{
device->cdata=0;
device->packet.valid=1;
device->found=0;
printcpacket(device->packet,"failed ");
}
}
getcpacket(frag,device);
}
return device->packet;
}
void printcpacket(struct cpacket packet,char *prefix)
{
int x;
printf("\n%s: addr:%.2x ctrl:%.2x len:%.2x crc:%.4x",prefix,packet.addr,packet.ctrl,packet.length,packet.checksum);
if(packet.length>>2)
{
printf(" -> ");
char id=packet.data[1];
switch(packet.data[0]&0x0f)
{
case 0:
printf("%s :%s",msgtype[packet.data[0]&0x0f].name,NULL);
break;
case 3:
printf("%s :%s",msgtype[packet.data[0]&0x0f].name,getstring(cctype,id,256));
break;
case 4:
printf("%s :%s",msgtype[packet.data[0]&0x0f].name,getstring(sstype,id,256));
break;
case 5:
printf("%s :%s",msgtype[packet.data[0]&0x0f].name,getstring(mmtype,id,256));
break;
case 6:
printf("%s :%s",msgtype[packet.data[0]&0x0f].name,NULL);
break;
case 7:
printf("%s :%s",msgtype[packet.data[0]&0x0f].name,NULL);
break;
default:
printf("reserved ");
break;
}
printf(" ");
for(x=0;x<(packet.length>>2);x++)
printf(" %.2x",packet.data[x]);
}
// printf("\n\n\n");
}

View File

@ -0,0 +1,177 @@
/*
* pcapstein dumps all B-Fields found in a pcap file
*
* 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.
*
* authors:
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
*
*/
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdint.h>
#include <pcap.h>
#include "pcapstein.h"
struct file_info fi;
void usage(void)
{
fprintf(stderr, "usage: pcapstein <dect-pcap-file>\n");
fprintf(stderr, " creates <dect-pcap-file>_pp.ima\n");
fprintf(stderr, " and <dect-pcap-file>_fp.ima\n");
fprintf(stderr, " for further g.721 audio processing\n");
fprintf(stderr, " e.g. decode and sox\n");
}
void init(char * fname)
{
fi.p = pcap_open_offline(fname, errbuf);
if (!fi.p)
{
fprintf(stderr, "couln't open(\"%s\"): %s\n",
fname,
strerror(errno));
fprintf(stderr, "pcap error: %s\n",
errbuf);
exit(1);
}
fprintf(stderr, "%s\n",
pcap_lib_version());
fprintf(stderr, "pcap file version %d.%d\n",
pcap_major_version(fi.p),
pcap_minor_version(fi.p)
);
/* output file handles */
char * imafname = malloc(strlen(fname)+23);
if (!imafname)
{
fprintf(stderr, "out of memory: %s\n",
strerror(errno));
exit(1);
}
/* PP output file */
sprintf(imafname, "%s_pp.ima", fname);
fi.fpp = open(imafname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (!fi.fpp)
{
fprintf(stderr, "couldn't open(\"%s\"): %s\n",
imafname,
strerror(errno));
exit(1);
}
/* FP output file */
sprintf(imafname, "%s_fp.ima", fname);
fi.ffp = open(imafname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (!fi.ffp)
{
fprintf(stderr, "couldn't open(\"%s\"): %s\n",
imafname,
strerror(errno));
exit(1);
}
free (imafname);
}
void process_b_field(const struct pcap_pkthdr *h, const u_char *pkt)
{
if ( (pkt[0x17] == 0x16) && (pkt[0x18] == 0x75) )
write(fi.fpp, &pkt[0x21], 40);
else
write(fi.ffp, &pkt[0x21], 40);
}
void process_pcap_packet(
u_char *user, const struct pcap_pkthdr *h,
const u_char *pkt)
{
#if 0
int i;
printf("packet for %s [%u/%u] @%d.%d\n",
user,
h->len,
h->caplen,
h->ts.tv_sec,
h->ts.tv_usec
);
#endif
if (pkt[ETH_TYPE_0_OFF] != ETH_TYPE_0)
return;
if (pkt[ETH_TYPE_1_OFF] != ETH_TYPE_1)
return;
#if 0
for (i=0; i<sizeof(dect_pkt_hdr); i++)
printf("%.2x ", pkt[i]);
printf("\n");
#endif
if ((pkt[PKT_OFF_H] & DECT_H_BA_MASK) == DECT_H_BA_NO_B_FIELD)
return;
if ((pkt[PKT_OFF_H] & DECT_H_BA_MASK) == DECT_H_BA_HALF_SLOT)
{
fprintf(stderr, "unsopported half slot\n");
return;
}
if ((pkt[PKT_OFF_H] & DECT_H_BA_MASK) == DECT_H_BA_DOUBLE_SLOT)
{
fprintf(stderr, "unsopported double slot\n");
return;
}
process_b_field(h, pkt);
#if 0
for (i=0; i<23; i++)
printf("%.2x ", pkt[i]);
printf("\n");
#endif
}
void play()
{
int ret;
ret = pcap_loop(
fi.p,
-1, /* forever */
process_pcap_packet,
"beckstein");
fprintf(stderr, "pcap_loop() = %d\n", ret);
if (*errbuf)
fprintf(stderr, "pcap error: %s\n", errbuf);
}
void shutdown()
{
pcap_close(fi.p);
close(fi.fpp);
close(fi.ffp);
}
int main(int argc, char ** argv)
{
if (argc != 2)
{
usage();
exit(1);
}
init(argv[1]);
play();
shutdown();
return 0;
}

View File

@ -0,0 +1,44 @@
/*
* pcapstein dumps all B-Fields found in a pcap file
*
* 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.
*
* authors:
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
*
*/
#ifndef PCAPSTEIN_H
#define PCAPSTEIN_H
struct file_info
{
pcap_t * p;
struct pcap_pkthdr rec; /* walks through all packets */
int fpp; /* filehandle to PP .ima file */
int ffp; /* filehandle to FP .ima file */
};
char errbuf[PCAP_ERRBUF_SIZE];
#define ETH_TYPE_0_OFF 0x0c
#define ETH_TYPE_1_OFF 0x0d
#define ETH_TYPE_0 0x23
#define ETH_TYPE_1 0x23
#define PKT_OFF_H 0x19
#define PKT_OFF_TAIL 0x1a
#define PKT_OFF_R_CRC 0x1f
#define PKT_OFF_B_FIELD 0x21
#define DECT_H_BA_MASK 0x0e
#define DECT_H_BA_NO_B_FIELD 0x0e
#define DECT_H_BA_HALF_SLOT 0x08
#define DECT_H_BA_DOUBLE_SLOT 0x04
#endif /* PCAPSTEIN_H */