Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ The devices typically come preloaded and do not need to be reflashed for basic u
The hardware is open-source at https://github.com/riverloopsec/apimote.
It is available assembled by contacting team at riverloopsecurity dot com.

In case of problems identifying the hardware try to run the following command (present in [GoodFET](https://github.com/travisgoodspeed/goodfet/blob/master/firmware/apps/radios/ccspi.c)) before any killerbee command

`~/goodfet/client$ sudo ./goodfet.monitor listapps full`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're going to move this to the FAQs if that's OK. @taylorcenters is preparing the update off of this PR that includes that.

_This is currently supported for beta, and supports sniffing, injection, and jamming._

Texas Instruments CC2530/1 EMK:
Expand Down
577 changes: 577 additions & 0 deletions firmware/apimotev4_202011.hex

Large diffs are not rendered by default.

57 changes: 24 additions & 33 deletions killerbee/GoodFET.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ def read(self,length):
while len(data)<length:
data=data+self.sock.recv(length-len(data));
return data;

class GoodFET:
"""GoodFET Client Library"""

Expand Down Expand Up @@ -178,7 +177,7 @@ def pyserInit(self, port, timeout, attemptlimit):

baud=115200;
if(os.environ.get("platform")=='arduino' or os.environ.get("board")=='arduino'):
baud=19200 #Slower, for now.
baud=19200; #Slower, for now.
self.serialport = serial.Serial(
port,
#9600,
Expand All @@ -198,7 +197,7 @@ def pyserInit(self, port, timeout, attemptlimit):
return
elif attempts==2 and os.environ.get("board")!='telosb':
print "See the GoodFET FAQ about missing info flash.";
self.serialport.timeout = 0.2;
self.serialport.timeout=0.2;
elif attempts == 100:
print "Tried 100 times to connect and failed."
sys.stdout.write("Continuing to try forever.") # No newline
Expand All @@ -217,12 +216,12 @@ def pyserInit(self, port, timeout, attemptlimit):
elif (os.environ.get("board")=='z1'):
self.bslResetZ1(invokeBSL=0);
elif (os.environ.get("board")=='apimote1') or (os.environ.get("board")=='apimote'):
#Not needed for the apimote2
Comment thread
rmspeers marked this conversation as resolved.
#Explicitly set RTS and DTR to halt board.
self.serialport.setRTS(1);
self.serialport.setDTR(1);
#RTS pin, not DTR is used for reset.
self.serialport.setRTS(0);
#print "Resetting Apimote not yet tested.";
else:
#Explicitly set RTS and DTR to halt board.
self.serialport.setRTS(1);
Expand Down Expand Up @@ -262,36 +261,33 @@ def pyserInit(self, port, timeout, attemptlimit):
break;
if self.verbose: print "Connected after %02i attempts." % attempts;
self.mon_connected();
self.serialport.timeout = 12;
self.serialport.timeout=12;
def serClose(self):
self.serialport.close();

def telosSetSCL(self, level):
'''Helper function for support of the TelosB platform.'''
self.serialport.setRTS(not level)
def telosSetSDA(self, level):
'''Helper function for support of the TelosB platform.'''
self.serialport.setDTR(not level)

def telosI2CStart(self):
'''Helper function for support of the TelosB platform.'''
self.telosSetSDA(1)
self.telosSetSCL(1)
self.telosSetSDA(0)

def telosI2CStop(self):
'''Helper function for support of the TelosB platform.'''
self.telosSetSDA(0)
self.telosSetSCL(1)
self.telosSetSDA(1)

def telosI2CWriteBit(self, bit):
'''Helper function for support of the TelosB platform.'''
self.telosSetSCL(0)
self.telosSetSDA(bit)
time.sleep(2e-6)
self.telosSetSCL(1)
time.sleep(1e-6)
self.telosSetSCL(0)

def telosI2CWriteByte(self, byte):
'''Helper function for support of the TelosB platform.'''
self.telosI2CWriteBit( byte & 0x80 );
self.telosI2CWriteBit( byte & 0x40 );
self.telosI2CWriteBit( byte & 0x20 );
Expand All @@ -301,21 +297,22 @@ def telosI2CWriteByte(self, byte):
self.telosI2CWriteBit( byte & 0x02 );
self.telosI2CWriteBit( byte & 0x01 );
self.telosI2CWriteBit( 0 ); # "acknowledge"

def telosI2CWriteCmd(self, addr, cmdbyte):
'''Helper function for support of the TelosB platform.'''
self.telosI2CStart()
self.telosI2CWriteByte( 0x90 | (addr << 1) )
self.telosI2CWriteByte( cmdbyte )
self.telosI2CStop()

def bslResetZ1(self, invokeBSL=0):
'''
Helper function for support of the Z1 mote platform.
Applies BSL entry sequence on RST/NMI and TEST/VPP pins.
By now only BSL mode is accessed.
@type invokeBSL: Integer
@param invokeBSL: 1 for a complete sequence, or 0 to only access RST/NMI pin
Applies BSL entry sequence on RST/NMI and TEST/VPP pins
Parameters:
invokeBSL = 1: complete sequence
invokeBSL = 0: only RST/NMI pin accessed

By now only BSL mode is accessed
'''

#if DEBUG > 1: sys.stderr.write("* bslReset(invokeBSL=%s)\n" % invokeBSL)
if invokeBSL:
#sys.stderr.write("in Z1 bsl reset...\n")
Expand All @@ -329,7 +326,6 @@ def bslResetZ1(self, invokeBSL=0):
self.writepicROM(0xFF, 0xFE)
time.sleep(0.1)
#sys.stderr.write("z1 reset done...\n")

def writepicROM(self, address, data):
''' Writes data to @address'''
for i in range(7,-1,-1):
Expand Down Expand Up @@ -384,8 +380,7 @@ def picROMfastclock(self, masterout):
time.sleep(0.02)
return self.serialport.getCTS()

def telosBReset(self, invokeBSL=0):
'''Helper function for support of the TelosB platform.'''
def telosBReset(self,invokeBSL=0):
# "BSL entry sequence at dedicated JTAG pins"
# rst !s0: 0 0 0 0 1 1
# tck !s1: 1 0 1 0 0 1
Expand Down Expand Up @@ -413,10 +408,10 @@ def telosBReset(self, invokeBSL=0):
time.sleep(0.250) #give MSP430's oscillator time to stabilize
self.serialport.flushInput() #clear buffers


def getbuffer(self,size=0x1c00):
writecmd(0,0xC2,[size&0xFF,(size>>16)&0xFF]);
print "Got %02x%02x buffer size." % (self.data[1],self.data[0]);

def writecmd(self, app, verb, count=0, data=[]):
"""Write a command and some data to the GoodFET."""
self.serialport.write(chr(app));
Expand Down Expand Up @@ -492,7 +487,6 @@ def readcmd(self):
#print "This shouldn't happen after syncing. Exiting for safety.";
#sys.exit(-1)
return self.data;

#Glitching stuff.
def glitchApp(self,app):
"""Glitch into a device by its application."""
Expand Down Expand Up @@ -533,6 +527,7 @@ def glitchRate(self,count=0x0800):
self.data);
#return ord(self.data[0]);


#Monitor stuff
def silent(self,s=0):
"""Transmissions halted when 1."""
Expand Down Expand Up @@ -625,7 +620,7 @@ def monitor_ram_depth(self):
self.writecmd(0,0x91,0,self.data);
return ord(self.data[0])+(ord(self.data[1])<<8);

#Baud rates
#Baud rates.
baudrates=[115200,
9600,
19200,
Expand All @@ -643,7 +638,7 @@ def setBaud(self,baud):
self.serialport.write(chr(baud));

print "Changed host baud."
self.serialport.baudrate = rates[baud];
self.serialport.setBaudrate(rates[baud]);
time.sleep(1);
self.serialport.flushInput()
self.serialport.flushOutput()
Expand All @@ -655,7 +650,7 @@ def readbyte(self):
def findbaud(self):
for r in self.baudrates:
print "\nTrying %i" % r;
self.serialport.baudrate = r;
self.serialport.setBaudrate(r);
#time.sleep(1);
self.serialport.flushInput()
self.serialport.flushOutput()
Expand All @@ -665,7 +660,6 @@ def findbaud(self):

print "Read %02x %02x %02x %02x" % (
self.readbyte(),self.readbyte(),self.readbyte(),self.readbyte());

def monitortest(self):
"""Self-test several functions through the monitor."""
print "Performing monitor self-test.";
Expand All @@ -683,7 +677,6 @@ def monitortest(self):
print "Echo test failed.";
print "Self-test complete.";
self.monitorclocking();

def monitorecho(self):
data="The quick brown fox jumped over the lazy dog.";
self.writecmd(self.MONITORAPP,0x81,len(data),data);
Expand Down Expand Up @@ -738,12 +731,11 @@ def monitorgetclock(self):
return 0xDEAD;
#Check for MSP430 before peeking this.
return self.MONpeek16(0x56);

# The following functions ought to be implemented in
# every client.
# every client.

def infostring(self):
if(os.environ.get("platform")=='arduino' or os.environ.get("board")=='arduino'):
#TODO implement in the ardunio client and remove special case from here
return "Arduino";
else:
a=self.MONpeek8(0xff0);
Expand Down Expand Up @@ -804,4 +796,3 @@ def pokeblock(self,address,bytes,memory="vn"):
def loadsymbols(self):
"""Load symbols from a file."""
return;

25 changes: 19 additions & 6 deletions killerbee/GoodFETCCSPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def setup(self):

#Set up the radio for ZigBee
self.strobe(0x01); #SXOSCON
self.strobe(0x01); #SXOSCON ## YL: idk why but needed to enable ram poking

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@travisgoodspeed - this appears that this PR just updates code from GoodFET repo, do you have insight into this change as the comment makes me wonder about it? https://github.com/travisgoodspeed/goodfet/blob/master/client/GoodFETCCSPI.py#L22

self.strobe(0x02); #SCAL
self.poke(0x11, 0x0AC2 & (~0x0800)); #MDMCTRL0, promiscuous
self.poke(0x12, 0x0500); #MDMCTRL1
Expand Down Expand Up @@ -76,12 +77,10 @@ def peek(self,reg,bytes=2):
bytes=2;

self.writecmd(self.CCSPIAPP,0x02,len(data),data);
try:
toret=( ord(self.data[2]) + (ord(self.data[1])<<8) );
except Exception as e:
print "issue in peeking for a register"
print e
toret=( (ord(self.data[1])<<8) );
toret=(
ord(self.data[2])+
(ord(self.data[1])<<8)
);
return toret;
def poke(self,reg,val,bytes=2):
"""Write a CCSPI Register."""
Expand Down Expand Up @@ -198,6 +197,20 @@ def pokeram(self,adr,data):
return;

lastpacket=range(0,0xff);

def RF_txrxpacket(self,packet,timeout=1):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using this for zbstumbler type use cases may be helpful to get a potentially quicker RX to a forged beacon request? CC @taylorcenters

data="\0";
self.data=data;
packet = [timeout&0xff, timeout>>8] + packet

self.writecmd(self.CCSPIAPP,0x86,len(packet),packet);
buffer=self.data;
self.lastpacket=buffer;
if(len(buffer)==0):
return None;

return buffer;

def RF_rxpacket(self):
"""Get a packet from the radio. Returns None if none is
waiting."""
Expand Down
2 changes: 1 addition & 1 deletion killerbee/GoodFETatmel128.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def pyserInit(self, port, timeout, attemptlimit):
break
if self.verbose:
print "Connected after %02i attempts." % attempts;
self.serialport.timeout = 12;
self.serialport.setTimeout(12);

def serClose(self):
self.connected = 0
Expand Down
32 changes: 24 additions & 8 deletions killerbee/dev_apimote.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
CC2420_REG_SYNC = 0x14

class APIMOTE:

packet_queue = None

def __init__(self, dev, revision=DEFAULT_REVISION):
'''
Instantiates the KillerBee class for the ApiMote platform running GoodFET firmware.
Expand Down Expand Up @@ -187,17 +190,30 @@ def pnext(self, timeout=100):
if self.__stream_open == False:
self.sniffer_on()

packet = None
start = datetime.utcnow()
if self.packet_queue is not None:
packet = self.packet_queue
self.packet_queue = None
frame = packet
rssi = self.packet_queue_rssi

else:
packet = None

start = datetime.utcnow()

while (packet is None and (start + timedelta(microseconds=timeout) > datetime.utcnow())):
packet = self.handle.RF_rxpacket()
rssi = self.handle.RF_getrssi() #TODO calibrate

if packet is None:
return None

while (packet is None and (start + timedelta(microseconds=timeout) > datetime.utcnow())):
packet = self.handle.RF_rxpacket()
rssi = self.handle.RF_getrssi() #TODO calibrate
if ord(packet[0])+1 < len(packet):
self.packet_queue = packet[ord(packet[0])+1+1:]
self.packet_queue_rssi = rssi

if packet is None:
return None
frame = packet[1:ord(packet[0])+1]

frame = packet[1:]
validcrc = False
if frame[-2:] == makeFCS(frame[:-2]):
validcrc = True
Expand Down
2 changes: 1 addition & 1 deletion killerbee/kbutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ def isgoodfetccspi(serialdev):
os.environ["board"] = "apimote2" #set enviroment variable for GoodFET code to use
gf = GoodFETCCSPI()
try:
gf.serInit(port=serialdev, attemptlimit=2)
gf.serInit(port=serialdev, attemptlimit=30)
#gf.setup()
except serial.serialutil.SerialException as e:
raise KBInterfaceError("Serial issue in kbutils.isgoodfetccspi: %s." % e)
Expand Down
1 change: 1 addition & 0 deletions killerbee/scapy_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from scapy.base_classes import SetGen
from scapy.packet import Gen, Raw
from scapy.all import *
from scapy import plist

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good fix!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue already reported and fixed at #207

# This line will allow KillerBee's pcap reader to overwrite scapy's reader that is imported on the
# above line, per suggestion from cutaway at https://code.google.com/p/killerbee/issues/detail?id=28:
from killerbee import *
Expand Down