diff --git a/.gitignore b/.gitignore index 811266435..5cdd4b63b 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,7 @@ *.ihex *.pyc *~ -obj_* +build/* Makefile.target Makefile.*.defines tools/doxygen/html diff --git a/.travis.yml b/.travis.yml index d9c98d75d..29e853d0e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,12 +34,22 @@ before_install: - if [ ${BUILD_COOJA:-false} = true ] ; then ant -q -f $CNG_HOST_PATH/tools/cooja/build.xml jar ; fi + + # Create a directory for out of tree tests and clone the test repo therein + # The directory will need created unconditionally so we can always chgrp and + # mount it, even if empty. Checkout a pre-defined version. + - mkdir -p $OUT_OF_TREE_TEST_PATH + - if [ ${TEST_NAME} = "out-of-tree-build" ] ; then + git clone --depth 1 https://github.com/contiki-ng/out-of-tree-tests $OUT_OF_TREE_TEST_PATH && + cd $OUT_OF_TREE_TEST_PATH && + git checkout $OUT_OF_TREE_TEST_VER ; + fi # Set permissions for Docker mount - - sudo chgrp -hR 1000 $CNG_HOST_PATH + - sudo chgrp -hR 1000 $CNG_HOST_PATH $OUT_OF_TREE_TEST_PATH # The test script for each build script: - - docker run --privileged -v $CNG_HOST_PATH:/home/user/contiki-ng -ti $DOCKER_IMG bash --login -c "make -C tests/??-$TEST_NAME"; + - docker run --privileged -v $OUT_OF_TREE_TEST_PATH:/home/user/out-of-tree-tests -v $CNG_HOST_PATH:/home/user/contiki-ng -ti $DOCKER_IMG bash --login -c "make -C tests/??-$TEST_NAME"; # Check outcome of the test - $CNG_HOST_PATH/tests/check-test.sh $CNG_HOST_PATH/tests/??-$TEST_NAME; exit $?; @@ -49,6 +59,8 @@ env: global: - DOCKER_IMG='contiker/contiki-ng' - CNG_HOST_PATH=`pwd` + - OUT_OF_TREE_TEST_PATH=$HOME/out-of-tree-tests + - OUT_OF_TREE_TEST_VER=2869ae7 # Encrypted environment variables. # Only available on builds of contiki-ng/contiki-ng branches, not PRs or forks. - secure: 0nrV5yjpT2kE19Hlm7t619Qbmyjx/G7bSUI1c+U3kZbyuxnRlASjVcDN5uPBoimIfGiBRI0nRq690BogAJt4EKwbC1Dy8kC1XD8mRtQ2AIZ6PHaUoG9iS5sBhFBQK0XkB83bwh6omRn/04O0uuX74ooSWT7fDrWxi/y5+0ysXK6gRtOhdrJ3FU5OkNVewX8NeCdx3pOWhMOtXWdFkMIi1XRdDnvMM5/hHlHMkdXXtaZQX9UsK3Q3DSjPRLZjKRiOlcx9MIg2ebh9ITmd2Du2p2q/LKtoutJckvhbKQPWcZi/B+1ZTSff0FHBIg+EYxf6TeFuia7XSTWH7sr2CDCCtcvSR9bB5yW6jdmGfa8Af8I1TCBuqoSUo0Re50BZBZF7COleEh+IojbjXn2CIDMg5rT4Sh3qcMGvFn9OW1cz5h5UNSOk7EIAXXPcI7Aloxh2sBo4/DrvvbfIsKrvxV9Fx4bdyNtR7dZ7xsoOw6L0zttC3K9naf3VAOeBAyjBiRwm0tWxJC/buhTsKlYrthhyUrwLtYAFL4UHcazvz57hY/cEzR2X6F//9Hp7HFoNtn1E36doX3ZfeI22yxHMo9SYW7O69C45wbhJ29lAA9XXbYVyGBKFkY8C1NCZ0Xckt9H8/Ow5Sz8HmW/NNBJCn0Fsx+jezdGc4ED5naugNbLAyNg= @@ -69,3 +81,4 @@ env: - TEST_NAME='native-runs' - TEST_NAME='ipv6' BUILD_COOJA=true - TEST_NAME='ipv6-nbr' BUILD_COOJA=true + - TEST_NAME='out-of-tree-build' diff --git a/Makefile.include b/Makefile.include index a194274bd..672c7f4c1 100644 --- a/Makefile.include +++ b/Makefile.include @@ -13,8 +13,6 @@ include $(CONTIKI)/Makefile.identify-target ### Include Makefile.tools to pull in targets that allow us to build tools dir include $(CONTIKI)/Makefile.tools -CONTIKI_NG_TARGET_LIB = contiki-ng-$(TARGET).a - ifeq ($(DEFINES),) -include Makefile.$(TARGET).defines ifneq ($(DEFINES),) @@ -39,7 +37,12 @@ ifdef CI endif endif -OBJECTDIR = obj_$(TARGET) +BUILD_DIR = build +BUILD_DIR_TARGET = $(BUILD_DIR)/$(TARGET) +BUILD_DIR_BOARD = $(BUILD_DIR_TARGET)/$(BOARD)/$(BUILD_DIR_CONFIG) +OBJECTDIR = $(BUILD_DIR_BOARD)/obj + +CONTIKI_NG_TARGET_LIB = $(BUILD_DIR_BOARD)/contiki-ng-$(TARGET).a LOWERCASE = -abcdefghijklmnopqrstuvwxyz/ UPPERCASE = _ABCDEFGHIJKLMNOPQRSTUVWXYZ_ @@ -75,10 +78,6 @@ endef CONTIKI_OBJECTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(CONTIKI_SOURCEFILES)}} PROJECT_OBJECTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(PROJECT_SOURCEFILES)}} -# Provide way to create $(OBJECTDIR) if it has been removed by make clean -$(OBJECTDIR): - mkdir $@ - uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1))) ### Include target makefile (TODO Unsafe?) @@ -124,6 +123,11 @@ endif # $(BOARD) not empty PLATFORM_ACTION ?= build +# Provide way to create $(OBJECTDIR) if it has been removed by make clean +$(OBJECTDIR): + $(TRACE_MKDIR) + $(Q)mkdir -p $@ + ifneq ($(BOARD),) TARGET_BOARD_UPPERCASE := ${strip ${shell echo $(BOARD) | sed y!$(LOWERCASE)!$(UPPERCASE)!}} CFLAGS += -DCONTIKI_BOARD_$(TARGET_BOARD_UPPERCASE)=1 @@ -241,12 +245,20 @@ ifeq ($(V),1) TRACE_LD = TRACE_AR = TRACE_AS = + TRACE_OBJCOPY = + TRACE_OBJDUMP = + TRACE_MKDIR = + TRACE_CP = Q= else TRACE_CC = @echo " CC " $< TRACE_LD = @echo " LD " $@ TRACE_AR = @echo " AR " $@ TRACE_AS = @echo " AS " $< + TRACE_OBJCOPY = @echo " OBJCOPY " $< "-->" $@ + TRACE_OBJDUMP = @echo " OBJDUMP " $< "-->" $@ + TRACE_MKDIR = @echo " MKDIR " $@ + TRACE_CP = @echo " CP " $< "-->" $@ Q=@ endif @@ -303,14 +315,13 @@ endef ### Harmonize filename of a .map file, if the platform's build system wants ### to create one -CONTIKI_NG_PROJECT_MAP = $(addsuffix -$(TARGET).map, $(basename $@)) +CONTIKI_NG_PROJECT_MAP = $(BUILD_DIR_BOARD)/$(basename $(notdir $@)).map .PHONY: clean distclean usage help targets boards savetarget savedefines viewconf clean: - -$(Q)rm -f *.d *.e *.o $(CONTIKI_NG_TARGET_LIB) $(CLEAN) - -$(Q)rm -rf $(OBJECTDIR) - -$(Q)rm -f $(addsuffix -$(TARGET).map, $(CONTIKI_PROJECT)) + -$(Q)rm -f *.d *.e *.o $(CLEAN) + -$(Q)rm -rf $(BUILD_DIR_TARGET) -$(Q)rm -f $(addsuffix .$(TARGET), $(CONTIKI_PROJECT)) @echo Target $(TARGET) cleaned @@ -319,6 +330,7 @@ distclean: echo Running: $(MAKE) TARGET=$$TARG clean; \ $(MAKE) TARGET=$$TARG clean; \ done + -$(Q)rm -rf $(BUILD_DIR) -include $(CONTIKI)/arch/platform/$(TARGET)/Makefile.customrules-$(TARGET) @@ -383,12 +395,16 @@ ifndef LD endif ifndef CUSTOM_RULE_LINK -%.$(TARGET): %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(CONTIKI_NG_TARGET_LIB) +$(BUILD_DIR_BOARD)/%.$(TARGET): %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(CONTIKI_NG_TARGET_LIB) $(TRACE_LD) $(Q)$(LD) $(LDFLAGS) $(TARGET_STARTFILES) ${filter-out %.a,$^} \ ${filter %.a,$^} $(TARGET_LIBFILES) -o $@ endif +%.$(TARGET): $(BUILD_DIR_BOARD)/%.$(TARGET) + $(TRACE_CP) + $(Q)cp $< $@ + %.ramprof: %.$(TARGET) $(NM) -S -td --size-sort $< | grep -i " [abdrw] " | cut -d' ' -f2,4 @@ -446,9 +462,9 @@ ifeq ($(findstring $(TARGET),native cooja),) include $(CONTIKI)/Makefile.embedded endif -# Don't treat %.$(TARGET) as an intermediate file because it is -# in fact the primary target. -.PRECIOUS: %.$(TARGET) +# Don't treat $(BUILD_DIR_BOARD)/%.$(TARGET) and $(TARGET) as intermediate +# files because for many platforms they are in fact the primary target. +.PRECIOUS: $(BUILD_DIR_BOARD)/%.$(TARGET) %.$(TARGET) # Cancel the predefined implict rule for compiling and linking # a single C source into a binary to force GNU make to consider diff --git a/arch/cpu/arm/Makefile.arm b/arch/cpu/arm/Makefile.arm index 83f9b8a36..e8befdb86 100644 --- a/arch/cpu/arm/Makefile.arm +++ b/arch/cpu/arm/Makefile.arm @@ -1,3 +1,11 @@ +### Verbosity control. Use make V=1 to get verbose builds. +### Extends what we already have in the top-level Makefile +ifeq ($(V),1) + TRACE_SREC_CAT = +else + TRACE_SREC_CAT = @echo " SREC_CAT " $< "-->" $@ +endif + CC = arm-none-eabi-gcc CPP = arm-none-eabi-cpp LD = arm-none-eabi-gcc @@ -43,22 +51,32 @@ endif ### CPU-dependent cleanup files CLEAN += *.elf *.bin *.lst *.hex *.i16hex +OUT_HEX = $(BUILD_DIR_BOARD)/%.hex +OUT_I16HEX = $(BUILD_DIR_BOARD)/%.i16hex +OUT_BIN = $(BUILD_DIR_BOARD)/%.bin +OUT_LST = $(BUILD_DIR_BOARD)/%.lst + ### Don't treat the following files as intermediate -.PRECIOUS: %.elf %.hex %.bin +.PRECIOUS: $(OUT_ELF) $(OUT_HEX) $(OUT_BIN) -%.i16hex: %.elf - $(OBJCOPY) -O ihex $< $@ +$(OUT_I16HEX): $(OUT_ELF) + $(TRACE_OBJCOPY) + $(Q)$(OBJCOPY) -O ihex $< $@ -%.hex: %.i16hex - $(SREC_CAT) $< -intel -o $@ -intel +$(OUT_HEX): $(OUT_I16HEX) + $(TRACE_SREC_CAT) + $(Q)$(SREC_CAT) $< -intel -o $@ -intel -%.bin: %.elf - $(OBJCOPY) -O binary $(OBJCOPY_FLAGS) $< $@ +$(OUT_BIN): $(OUT_ELF) + $(TRACE_OBJCOPY) + $(Q)$(OBJCOPY) -O binary $(OBJCOPY_FLAGS) $< $@ -%.lst: %.elf - $(OBJDUMP) $(OBJDUMP_FLAGS) $< > $@ +$(OUT_LST): $(OUT_ELF) + $(TRACE_OBJDUMP) + $(Q)$(OBJDUMP) $(OBJDUMP_FLAGS) $< > $@ ### We don't really need the .hex and .bin for the .$(TARGET) but let's make ### sure they get built -%.$(TARGET): %.elf %.hex %.bin - cp $< $@ +$(BUILD_DIR_BOARD)/%.$(TARGET): $(OUT_ELF) $(OUT_HEX) $(OUT_BIN) + $(TRACE_CP) + $(Q)cp $< $@ diff --git a/arch/cpu/arm/cortex-m/Makefile.cortex-m b/arch/cpu/arm/cortex-m/Makefile.cortex-m index aebcf2bdd..0ca1d54ff 100644 --- a/arch/cpu/arm/cortex-m/Makefile.cortex-m +++ b/arch/cpu/arm/cortex-m/Makefile.cortex-m @@ -3,11 +3,25 @@ CONTIKI_ARM_DIRS += cortex-m cortex-m/CMSIS ### Build syscalls for newlib MODULES += os/lib/newlib +LDFLAGS += -T $(LDSCRIPT) +LDFLAGS += -Wl,--gc-sections,--sort-section=alignment +LDFLAGS += -Wl,-Map=$(CONTIKI_NG_PROJECT_MAP),--cref,--no-warn-mismatch + +OBJCOPY_FLAGS += --gap-fill 0xff + +CPU_STARTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(CPU_START_SOURCEFILES)}} + +### Resolve any potential circular dependencies between the linked libraries +### See: https://stackoverflow.com/questions/5651869/gcc-what-are-the-start-group-and-end-group-command-line-options/5651895 +TARGET_LIBFLAGS := -Wl,--start-group $(TARGET_LIBFILES) -Wl,--end-group + CUSTOM_RULE_LINK = 1 +OUT_ELF = $(BUILD_DIR_BOARD)/%.elf + .SECONDEXPANSION: -%.elf: $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(LDSCRIPT) $(TARGET_LIBS) +$(OUT_ELF): $(CPU_STARTFILES) $$(CONTIKI_OBJECTFILES) %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(LDSCRIPT) $(TARGET_LIBS) $(TRACE_LD) $(Q)$(LD) $(LDFLAGS) ${filter-out $(LDSCRIPT) %.a,$^} ${filter %.a,$^} $(TARGET_LIBFLAGS) -o $@ diff --git a/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 b/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 index 3cf216bfb..b4bf612da 100644 --- a/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 +++ b/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 @@ -3,16 +3,7 @@ CONTIKI_ARM_DIRS += cortex-m/cm3 CFLAGS += -mcpu=cortex-m3 LDFLAGS += -mcpu=cortex-m3 -nostartfiles -LDFLAGS += -T $(LDSCRIPT) -LDFLAGS += -Wl,--gc-sections,--sort-section=alignment -LDFLAGS += -Wl,-Map=$(CONTIKI_NG_PROJECT_MAP),--cref,--no-warn-mismatch -OBJCOPY_FLAGS += --gap-fill 0xff - -CPU_STARTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(CPU_START_SOURCEFILES)}} - -### Resolve any potential circular dependencies between the linked libraries -### See: https://stackoverflow.com/questions/5651869/gcc-what-are-the-start-group-and-end-group-command-line-options/5651895 -TARGET_LIBFLAGS := -Wl,--start-group $(TARGET_LIBFILES) -lm -Wl,--end-group +TARGET_LIBFILES += -lm include $(CONTIKI)/arch/cpu/arm/cortex-m/Makefile.cortex-m diff --git a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 index b0b592e43..7443681ea 100644 --- a/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 +++ b/arch/cpu/arm/cortex-m/cm4/Makefile.cm4 @@ -3,16 +3,5 @@ CONTIKI_ARM_DIRS += cortex-m/cm4 CFLAGS += -mcpu=cortex-m4 LDFLAGS += -mcpu=cortex-m4 -LDFLAGS += -T $(LDSCRIPT) -LDFLAGS += -Wl,--gc-sections,--sort-section=alignment -LDFLAGS += -Wl,-Map=$(CONTIKI_NG_PROJECT_MAP),--cref,--no-warn-mismatch - -OBJCOPY_FLAGS += --gap-fill 0xff - -CPU_STARTFILES = ${addprefix $(OBJECTDIR)/,${call oname, $(CPU_START_SOURCEFILES)}} - -### Resolve any potential circular dependencies between the linked libraries -### See: https://stackoverflow.com/questions/5651869/gcc-what-are-the-start-group-and-end-group-command-line-options/5651895 -TARGET_LIBFLAGS := -Wl,--start-group $(TARGET_LIBFILES) -Wl,--end-group include $(CONTIKI)/arch/cpu/arm/cortex-m/Makefile.cortex-m diff --git a/arch/cpu/cc2538/dev/cc2538-rf.c b/arch/cpu/cc2538/dev/cc2538-rf.c index bddfcc942..e3a548067 100644 --- a/arch/cpu/cc2538/dev/cc2538-rf.c +++ b/arch/cpu/cc2538/dev/cc2538-rf.c @@ -140,6 +140,8 @@ static const output_config_t output_power[] = { {-24, 0x00 }, }; +static radio_result_t get_value(radio_param_t param, radio_value_t *value); + #define OUTPUT_CONFIG_COUNT (sizeof(output_power) / sizeof(output_config_t)) /* Max and Min Output Power in dBm */ @@ -394,6 +396,48 @@ get_sfd_timestamp(void) return RTIMER_NOW() - RADIO_TO_RTIMER(timer_val - sfd); } /*---------------------------------------------------------------------------*/ +/* Enable or disable radio test mode emmiting modulated or unmodulated + * (carrier) signal. See User's Guide pages 719 and 741. + */ +static uint32_t prev_FRMCTRL0, prev_MDMTEST1; +static uint8_t was_on; + +static void +set_test_mode(uint8_t enable, uint8_t modulated) +{ + radio_value_t mode; + get_value(RADIO_PARAM_POWER_MODE, &mode); + + if(enable) { + if(mode == RADIO_POWER_MODE_CARRIER_ON) { + return; + } + was_on = (mode == RADIO_POWER_MODE_ON); + off(); + prev_FRMCTRL0 = REG(RFCORE_XREG_FRMCTRL0); + /* This constantly transmits random data */ + REG(RFCORE_XREG_FRMCTRL0) = 0x00000042; + if(!modulated) { + prev_MDMTEST1 = REG(RFCORE_XREG_MDMTEST1); + /* ...adding this we send an unmodulated carrier instead */ + REG(RFCORE_XREG_MDMTEST1) = 0x00000018; + } + CC2538_RF_CSP_ISTXON(); + } else { + if(mode != RADIO_POWER_MODE_CARRIER_ON) { + return; + } + CC2538_RF_CSP_ISRFOFF(); + REG(RFCORE_XREG_FRMCTRL0) = prev_FRMCTRL0; + if(!modulated) { + REG(RFCORE_XREG_MDMTEST1) = prev_MDMTEST1; + } + if(was_on) { + on(); + } + } +} +/*---------------------------------------------------------------------------*/ /* Netstack API radio driver functions */ /*---------------------------------------------------------------------------*/ static int @@ -806,8 +850,12 @@ get_value(radio_param_t param, radio_value_t *value) switch(param) { case RADIO_PARAM_POWER_MODE: - *value = (REG(RFCORE_XREG_RXENABLE) && RFCORE_XREG_RXENABLE_RXENMASK) == 0 - ? RADIO_POWER_MODE_OFF : RADIO_POWER_MODE_ON; + if((REG(RFCORE_XREG_RXENABLE) & RFCORE_XREG_RXENABLE_RXENMASK) == 0) { + *value = RADIO_POWER_MODE_OFF; + } else { + *value = (REG(RFCORE_XREG_FRMCTRL0) & RFCORE_XREG_FRMCTRL0_TX_MODE) == 0 + ? RADIO_POWER_MODE_ON : RADIO_POWER_MODE_CARRIER_ON; + } return RADIO_RESULT_OK; case RADIO_PARAM_CHANNEL: *value = (radio_value_t)get_channel(); @@ -896,6 +944,11 @@ set_value(radio_param_t param, radio_value_t value) off(); return RADIO_RESULT_OK; } + if(value == RADIO_POWER_MODE_CARRIER_ON || + value == RADIO_POWER_MODE_CARRIER_OFF) { + set_test_mode((value == RADIO_POWER_MODE_CARRIER_ON), 0); + return RADIO_RESULT_OK; + } return RADIO_RESULT_INVALID_VALUE; case RADIO_PARAM_CHANNEL: if(value < CC2538_RF_CHANNEL_MIN || diff --git a/arch/cpu/cc26x0-cc13x0/Makefile.cc26x0-cc13x0 b/arch/cpu/cc26x0-cc13x0/Makefile.cc26x0-cc13x0 index e62b8be05..c7fb7b95e 100644 --- a/arch/cpu/cc26x0-cc13x0/Makefile.cc26x0-cc13x0 +++ b/arch/cpu/cc26x0-cc13x0/Makefile.cc26x0-cc13x0 @@ -81,8 +81,10 @@ STACK_SIZE = 0 @$(SIZE) -A $< | egrep "data|bss" | awk '{s+=$$2} END {s=s+$(STACK_SIZE); f=$(RAM_SIZE)-s; printf "[RAM] used %6d, free %6d\n",s,f;}' @$(SIZE) -A $< | egrep "text|isr_vector" | awk '{s+=$$2} END {f=$(FLASH_SIZE)-s; printf "[Flash] used %6d, free %6d\n",s,f;}' +include $(CONTIKI)/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 + ifeq ($(BOARD_SUPPORTS_BSL),1) -%.upload: %.bin +%.upload: $(OUT_BIN) ifeq ($(wildcard $(BSL)), ) @echo "ERROR: Could not find the cc2538-bsl script. Did you run 'git submodule update --init' ?" else @@ -95,5 +97,3 @@ endif ### For the login etc targets BAUDRATE = 115200 - -include $(CONTIKI)/arch/cpu/arm/cortex-m/cm3/Makefile.cm3 diff --git a/arch/cpu/nrf52832/Makefile.nrf52832 b/arch/cpu/nrf52832/Makefile.nrf52832 index c97c728e5..098033ce4 100644 --- a/arch/cpu/nrf52832/Makefile.nrf52832 +++ b/arch/cpu/nrf52832/Makefile.nrf52832 @@ -172,11 +172,11 @@ vpath %.s $(ASM_PATHS) OBJECTS = $(C_OBJECTS) $(ASM_OBJECTS) -CLEAN += nrf52832.a +NRFLIB = $(BUILD_DIR_BOARD)/nrf52832.a -TARGET_LIBS = nrf52832.a $(NRF52_SDK_ROOT)/components/iot/ble_6lowpan/lib/ble_6lowpan.a +TARGET_LIBS = $(NRFLIB) $(NRF52_SDK_ROOT)/components/iot/ble_6lowpan/lib/ble_6lowpan.a -nrf52832.a: $(OBJECTS) +$(NRFLIB): $(OBJECTS) $(TRACE_AR) $(Q)$(AR) $(AROPTS) $@ $^ diff --git a/arch/cpu/nrf52832/ble/ble-mac.c b/arch/cpu/nrf52832/ble/ble-mac.c index 4fe1ef934..d604a911d 100644 --- a/arch/cpu/nrf52832/ble/ble-mac.c +++ b/arch/cpu/nrf52832/ble/ble-mac.c @@ -347,6 +347,12 @@ off(void) return 1; } /*---------------------------------------------------------------------------*/ +static int +max_payload(void) +{ + return PACKETBUF_SIZE; +} +/*---------------------------------------------------------------------------*/ static void init(void) { @@ -371,7 +377,8 @@ const struct mac_driver ble_ipsp_mac_driver = { send_packet, NULL, on, - off + off, + max_payload }; /*---------------------------------------------------------------------------*/ /** diff --git a/arch/dev/cc2420/cc2420.c b/arch/dev/cc2420/cc2420.c index a1572b0ef..545f917ac 100644 --- a/arch/dev/cc2420/cc2420.c +++ b/arch/dev/cc2420/cc2420.c @@ -114,6 +114,7 @@ PROCESS(cc2420_process, "CC2420 driver"); #define CORR_THR(n) (((n) & 0x1f) << 6) #define FIFOP_THR(n) ((n) & 0x7f) #define RXBPF_LOCUR (1 << 13); +#define TX_MODE (3 << 2) int cc2420_on(void); int cc2420_off(void); @@ -135,6 +136,8 @@ static void set_poll_mode(uint8_t enable); static void set_send_on_cca(uint8_t enable); static void set_auto_ack(uint8_t enable); +static void set_test_mode(uint8_t enable, uint8_t modulated); + signed char cc2420_last_rssi; uint8_t cc2420_last_correlation; @@ -156,7 +159,11 @@ get_value(radio_param_t param, radio_value_t *value) } switch(param) { case RADIO_PARAM_POWER_MODE: - *value = receive_on ? RADIO_POWER_MODE_ON : RADIO_POWER_MODE_OFF; + if((getreg(CC2420_MDMCTRL1) & TX_MODE) & 0x08) { + *value = RADIO_POWER_MODE_CARRIER_ON; + } else { + *value = receive_on ? RADIO_POWER_MODE_ON : RADIO_POWER_MODE_OFF; + } return RADIO_RESULT_OK; case RADIO_PARAM_CHANNEL: *value = cc2420_get_channel(); @@ -237,6 +244,11 @@ set_value(radio_param_t param, radio_value_t value) cc2420_off(); return RADIO_RESULT_OK; } + if(value == RADIO_POWER_MODE_CARRIER_ON || + value == RADIO_POWER_MODE_CARRIER_OFF) { + set_test_mode((value == RADIO_POWER_MODE_CARRIER_ON), 0); + return RADIO_RESULT_OK; + } return RADIO_RESULT_INVALID_VALUE; case RADIO_PARAM_CHANNEL: if(value < 11 || value > 26) { @@ -1120,3 +1132,45 @@ set_send_on_cca(uint8_t enable) send_on_cca = enable; } /*---------------------------------------------------------------------------*/ +/* Enable or disable radio test mode emmiting modulated or unmodulated + * (carrier) signal. See datasheet page 55. + */ +static uint16_t prev_MDMCTRL1, prev_DACTST; +static uint8_t was_on; + +static void +set_test_mode(uint8_t enable, uint8_t modulated) +{ + radio_value_t mode; + get_value(RADIO_PARAM_POWER_MODE, &mode); + + if(enable) { + if(mode == RADIO_POWER_MODE_CARRIER_ON) { + return; + } + was_on = (mode == RADIO_POWER_MODE_ON); + off(); + prev_MDMCTRL1 = getreg(CC2420_MDMCTRL1); + setreg(CC2420_MDMCTRL1, 0x050C); + if(!modulated) { + prev_DACTST = getreg(CC2420_DACTST); + setreg(CC2420_DACTST, 0x1800); + } + /* actually starts the test mode */ + strobe(CC2420_STXON); + } else { + if(mode != RADIO_POWER_MODE_CARRIER_ON) { + return; + } + strobe(CC2420_SRFOFF); + if(!modulated) { + setreg(CC2420_DACTST, prev_DACTST); + } + setreg(CC2420_MDMCTRL1, prev_MDMCTRL1); + /* actually stops the carrier */ + if(was_on) { + on(); + } + } +} +/*---------------------------------------------------------------------------*/ diff --git a/arch/platform/cc2538dk/Makefile.cc2538dk b/arch/platform/cc2538dk/Makefile.cc2538dk index d80fd8d5f..148c6e837 100644 --- a/arch/platform/cc2538dk/Makefile.cc2538dk +++ b/arch/platform/cc2538dk/Makefile.cc2538dk @@ -28,11 +28,12 @@ endif BSL = $(CONTIKI)/tools/cc2538-bsl/cc2538-bsl.py -%.upload: %.bin %.elf +%.upload: $(OUT_BIN) $(OUT_ELF) ifeq ($(wildcard $(BSL)), ) @echo "ERROR: Could not find the cc2538-bsl script. Did you run 'git submodule update --init' ?" else - $(eval BSL_ADDRESS_ARG := -a $(shell $(OBJDUMP) -h $*.elf | grep -B1 LOAD | \ + $(eval BSL_ADDRESS_ARG := -a $(shell $(OBJDUMP) -h \ + $(BUILD_DIR_BOARD)/$*.elf | grep -B1 LOAD | \ grep -Ev 'LOAD|\-\-' | awk '{print "0x" $$5}' | \ sort -g | head -1)) $(PYTHON) $(BSL) $(BSL_FLAGS) $(BSL_ADDRESS_ARG) $< diff --git a/arch/platform/cooja/Makefile.cooja b/arch/platform/cooja/Makefile.cooja index d06aa08d5..6a6a9d49e 100644 --- a/arch/platform/cooja/Makefile.cooja +++ b/arch/platform/cooja/Makefile.cooja @@ -34,10 +34,10 @@ endif endif ## QUICKSTART -#MAIN_SRC = $(OBJECTDIR)/$(LIBNAME).c -MAIN_OBJ = $(OBJECTDIR)/$(LIBNAME).o -ARCHIVE = $(OBJECTDIR)/$(LIBNAME).a -JNILIB = $(OBJECTDIR)/$(LIBNAME).$(TARGET) +#MAIN_SRC = $(BUILD_DIR_BOARD)/$(LIBNAME).c +MAIN_OBJ = $(BUILD_DIR_BOARD)/$(LIBNAME).o +ARCHIVE = $(BUILD_DIR_BOARD)/$(LIBNAME).a +JNILIB = $(BUILD_DIR_BOARD)/$(LIBNAME).$(TARGET) CONTIKI_APP_OBJ = $(CONTIKI_APP).o ### COOJA platform sources diff --git a/arch/platform/cooja/Makefile.customrules-cooja b/arch/platform/cooja/Makefile.customrules-cooja index 42d6e125e..60d6240f1 100644 --- a/arch/platform/cooja/Makefile.customrules-cooja +++ b/arch/platform/cooja/Makefile.customrules-cooja @@ -10,11 +10,11 @@ CUSTOM_RULE_LINK=1 REDEF_PRINTF=1 # Redefine functions to enable printf()s inside Cooja -# NB: Assumes ARCHIVE was not overridden and is in $(OBJECTDIR) +# NB: Assumes ARCHIVE was not overridden and is in $(BUILD_DIR_BOARD) $(ARCHIVE): $(CONTIKI_OBJECTFILES) | $(OBJECTDIR) $(AR_COMMAND_1) $^ $(AR_COMMAND_2) -# NB: Assumes JNILIB was not overridden and is in $(OBJECTDIR) +# NB: Assumes JNILIB was not overridden and is in $(BUILD_DIR_BOARD) $(JNILIB): $(CONTIKI_APP_OBJ) $(MAIN_OBJ) $(PROJECT_OBJECTFILES) $(ARCHIVE) | $(OBJECTDIR) ifdef REDEF_PRINTF diff --git a/arch/platform/jn516x/Makefile.jn516x b/arch/platform/jn516x/Makefile.jn516x index 9ad9488d5..051c336fb 100644 --- a/arch/platform/jn516x/Makefile.jn516x +++ b/arch/platform/jn516x/Makefile.jn516x @@ -229,30 +229,34 @@ ALLLIBS = $(addprefix -l,$(LDLIBS)) $(addprefix -l,$(LDSTACKLIBS)) $(addprefix - ABS_APPLIBS = $(addsuffix _$(JENNIC_CHIP_FAMILY).a,$(addprefix $(COMPONENTS_BASE_DIR)/Library/lib,$(APPLIBS))) ifneq ($(wildcard $(SDK_BASE_DIR)/Components/Library/*),) -# The SDK is fully installed, proceed to linking and objcopy to ready-to-upload .jn516x.bin file -%.$(TARGET): %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(CONTIKI_NG_TARGET_LIB) $(ABS_APPLIBS) - echo ${filter %.a,$^} +# The SDK is fully installed, proceed to linking +$(BUILD_DIR_BOARD)/%.$(TARGET): %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(CONTIKI_NG_TARGET_LIB) $(ABS_APPLIBS) + @echo ${filter %.a,$^} $(Q)$(CC) -Wl,--gc-sections $(LDFLAGS) -T$(LINKCMD) -o $@ -Wl,--start-group \ $(patsubst /cygdrive/c/%,c:/%,${filter-out %.a,$^}) \ $(patsubst /cygdrive/c/%,c:/%,${filter %.a,$^}) \ $(ALLLIBS) -Wl,--end-group -Wl,-Map,$(CONTIKI_NG_PROJECT_MAP) - $(OBJCOPY) -S -O binary $@ $@.bin else # The SDK does not include libraries, only build objects and libraries, skip linking -%.$(TARGET): %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(CONTIKI_NG_TARGET_LIB) - echo Creating empty $@ +$(BUILD_DIR_BOARD)/%.$(TARGET): %.o $(PROJECT_OBJECTFILES) $(PROJECT_LIBRARIES) $(CONTIKI_NG_TARGET_LIB) + @echo Creating empty $@ touch $@ endif -%.$(TARGET).bin: %.$(TARGET) +$(BUILD_DIR_BOARD)/%.$(TARGET).bin: $(BUILD_DIR_BOARD)/%.$(TARGET) + $(TRACE_OBJCOPY) $(Q)$(OBJCOPY) -S -O binary $< $@ +%.$(TARGET).bin: $(BUILD_DIR_BOARD)/%.$(TARGET).bin + $(TRACE_CP) + $(Q)$(CP) $< $@ + ### Upload target to one jn516x mote specified by MOTE=portNumber ifeq ($(HOST_OS),Windows) -%.upload: %.$(TARGET).bin +%.upload: $(BUILD_DIR_BOARD)/%.$(TARGET).bin ${FLASH_PROGRAMMER} -a -c $(DEV_PORT) -B 1000000 -s -w -f $< else -%.upload: %.$(TARGET).bin +%.upload: $(BUILD_DIR_BOARD)/%.$(TARGET).bin ${FLASH_PROGRAMMER} -V 10 -v -s $(DEV_PORT) -I 38400 -P 1000000 -f $< endif @@ -276,7 +280,7 @@ motelistinfo: $(Q)$(MOTELIST) ${FLASH_PROGRAMMER} \? ### Upload target to all connected jn516x motes -%.uploadall: %.$(TARGET).bin +%.uploadall: $(BUILD_DIR_BOARD)/%.$(TARGET).bin $(Q)$(MOTELIST) ${FLASH_PROGRAMMER} $< ### Flash the given file to all connected jn516x motes diff --git a/arch/platform/openmote-cc2538/Makefile.openmote-cc2538 b/arch/platform/openmote-cc2538/Makefile.openmote-cc2538 index d3863fdbc..8b25b0bfe 100644 --- a/arch/platform/openmote-cc2538/Makefile.openmote-cc2538 +++ b/arch/platform/openmote-cc2538/Makefile.openmote-cc2538 @@ -35,11 +35,12 @@ endif BSL = $(CONTIKI)/tools/cc2538-bsl/cc2538-bsl.py -%.upload: %.bin %.elf +%.upload: $(OUT_BIN) $(OUT_ELF) ifeq ($(wildcard $(BSL)), ) @echo "ERROR: Could not find the cc2538-bsl script. Did you run 'git submodule update --init' ?" else - $(eval BSL_ADDRESS_ARG := -a $(shell $(OBJDUMP) -h $*.elf | grep -B1 LOAD | \ + $(eval BSL_ADDRESS_ARG := -a $(shell $(OBJDUMP) -h \ + $(BUILD_DIR_BOARD)/$*.elf | grep -B1 LOAD | \ grep -Ev 'LOAD|\-\-' | awk '{print "0x" $$5}' | \ sort -g | head -1)) $(PYTHON) $(BSL) $(BSL_FLAGS) $(BSL_ADDRESS_ARG) $< diff --git a/arch/platform/zoul/Makefile.zoul b/arch/platform/zoul/Makefile.zoul index 938abe035..e43f84744 100644 --- a/arch/platform/zoul/Makefile.zoul +++ b/arch/platform/zoul/Makefile.zoul @@ -69,9 +69,9 @@ endif ### $$$$ Double escapes $s that need to be passed to the shell - once for when ### make parses UPLOAD_RULE, and once for when the expanded rule is parsed by make. define UPLOAD_RULE -%.$(MOTE): %.bin %.elf +%.$(MOTE): $(OUT_BIN) $(OUT_ELF) @echo "Flashing $(MOTE)" - @BSL_ADDRESS=`$(OBJDUMP) -h $$*.elf | grep -B1 LOAD | \ + @BSL_ADDRESS=`$(OBJDUMP) -h $(BUILD_DIR_BOARD)/$$*.elf | grep -B1 LOAD | \ grep -Ev 'LOAD|\-\-' | awk '{print "0x" $$$$5}' | \ sort -g | head -1`; \ $(PYTHON) $(BSL) $(BSL_FLAGS) -b $(BSL_SPEED) -a $$$${BSL_ADDRESS} -p $(MOTE) $$< diff --git a/examples/platform-specific/cc26x0-cc13x0/Makefile.target b/examples/platform-specific/cc26x0-cc13x0/Makefile.target index 15890aa6a..bd54a4fc7 100644 --- a/examples/platform-specific/cc26x0-cc13x0/Makefile.target +++ b/examples/platform-specific/cc26x0-cc13x0/Makefile.target @@ -1 +1 @@ -TARGET = srf06-cc26xx +TARGET = cc26x0-cc13x0 diff --git a/examples/platform-specific/cc26x0-cc13x0/cc26x0-web-demo/Makefile.target b/examples/platform-specific/cc26x0-cc13x0/cc26x0-web-demo/Makefile.target index 15890aa6a..bd54a4fc7 100644 --- a/examples/platform-specific/cc26x0-cc13x0/cc26x0-web-demo/Makefile.target +++ b/examples/platform-specific/cc26x0-cc13x0/cc26x0-web-demo/Makefile.target @@ -1 +1 @@ -TARGET = srf06-cc26xx +TARGET = cc26x0-cc13x0 diff --git a/examples/platform-specific/cc26x0-cc13x0/very-sleepy-demo/Makefile.target b/examples/platform-specific/cc26x0-cc13x0/very-sleepy-demo/Makefile.target index 15890aa6a..bd54a4fc7 100644 --- a/examples/platform-specific/cc26x0-cc13x0/very-sleepy-demo/Makefile.target +++ b/examples/platform-specific/cc26x0-cc13x0/very-sleepy-demo/Makefile.target @@ -1 +1 @@ -TARGET = srf06-cc26xx +TARGET = cc26x0-cc13x0 diff --git a/examples/rpl-udp/udp-client.c b/examples/rpl-udp/udp-client.c index 1fb030034..7f24c8bac 100644 --- a/examples/rpl-udp/udp-client.c +++ b/examples/rpl-udp/udp-client.c @@ -32,16 +32,21 @@ udp_rx_callback(struct simple_udp_connection *c, const uint8_t *data, uint16_t datalen) { - unsigned count = *(unsigned *)data; - LOG_INFO("Received response %u from ", count); + + LOG_INFO("Received response '%.*s' from ", datalen, (char *) data); LOG_INFO_6ADDR(sender_addr); +#if LLSEC802154_CONF_ENABLED + LOG_INFO_(" LLSEC LV:%d", uipbuf_get_attr(UIPBUF_ATTR_LLSEC_LEVEL)); +#endif LOG_INFO_("\n"); + } /*---------------------------------------------------------------------------*/ PROCESS_THREAD(udp_client_process, ev, data) { static struct etimer periodic_timer; static unsigned count; + static char str[32]; uip_ipaddr_t dest_ipaddr; PROCESS_BEGIN(); @@ -59,7 +64,8 @@ PROCESS_THREAD(udp_client_process, ev, data) LOG_INFO("Sending request %u to ", count); LOG_INFO_6ADDR(&dest_ipaddr); LOG_INFO_("\n"); - simple_udp_sendto(&udp_conn, &count, sizeof(count), &dest_ipaddr); + snprintf(str, sizeof(str), "hello %d", count); + simple_udp_sendto(&udp_conn, str, strlen(str), &dest_ipaddr); count++; } else { LOG_INFO("Not reachable yet\n"); diff --git a/examples/rpl-udp/udp-server.c b/examples/rpl-udp/udp-server.c index 399cabfc4..072eb8ae8 100644 --- a/examples/rpl-udp/udp-server.c +++ b/examples/rpl-udp/udp-server.c @@ -54,15 +54,13 @@ udp_rx_callback(struct simple_udp_connection *c, const uint8_t *data, uint16_t datalen) { - unsigned count = *(unsigned *)data; - LOG_INFO("Received request %u from ", count); + LOG_INFO("Received request '%.*s' from ", datalen, (char *) data); LOG_INFO_6ADDR(sender_addr); LOG_INFO_("\n"); #if WITH_SERVER_REPLY - LOG_INFO("Sending response %u to ", count); - LOG_INFO_6ADDR(sender_addr); - LOG_INFO_("\n"); - simple_udp_sendto(&udp_conn, &count, sizeof(count), sender_addr); + /* send back the same string to the client as an echo reply */ + LOG_INFO("Sending response.\n"); + simple_udp_sendto(&udp_conn, data, datalen, sender_addr); #endif /* WITH_SERVER_REPLY */ } /*---------------------------------------------------------------------------*/ diff --git a/os/dev/radio.h b/os/dev/radio.h index e6ca64f3d..e279e9efe 100644 --- a/os/dev/radio.h +++ b/os/dev/radio.h @@ -196,7 +196,9 @@ enum { /* Radio power modes */ enum { RADIO_POWER_MODE_OFF, - RADIO_POWER_MODE_ON + RADIO_POWER_MODE_ON, + RADIO_POWER_MODE_CARRIER_ON, + RADIO_POWER_MODE_CARRIER_OFF }; /** diff --git a/os/lib/json/jsonparse.c b/os/lib/json/jsonparse.c index 6277b56c4..941420521 100644 --- a/os/lib/json/jsonparse.c +++ b/os/lib/json/jsonparse.c @@ -32,34 +32,42 @@ #include "jsonparse.h" #include #include +#include /*--------------------------------------------------------------------*/ -static int +static bool push(struct jsonparse_state *state, char c) { - state->stack[state->depth] = c; - state->depth++; - state->vtype = 0; - return state->depth < JSONPARSE_MAX_DEPTH; + if(state->depth < JSONPARSE_MAX_DEPTH) { + state->stack[state->depth] = c; + state->depth++; + state->vtype = 0; + return true; + } else { + return false; + } } /*--------------------------------------------------------------------*/ -static void +static bool modify(struct jsonparse_state *state, char c) { if(state->depth > 0) { state->stack[state->depth - 1] = c; + return true; + } else { + return false; } } /*--------------------------------------------------------------------*/ -static char +static bool pop(struct jsonparse_state *state) { if(state->depth == 0) { - return JSON_TYPE_ERROR; + return false; } state->depth--; state->vtype = state->stack[state->depth]; - return state->stack[state->depth]; + return true; } /*--------------------------------------------------------------------*/ /* will pass by the value and store the start and length of the value for @@ -134,15 +142,11 @@ skip_ws(struct jsonparse_state *state) } } /*--------------------------------------------------------------------*/ -static int +static bool is_atomic(struct jsonparse_state *state) { char v = state->vtype; - if(v == 'N' || v == '"' || v == '0' || v == 'n' || v == 't' || v == 'f') { - return 1; - } else { - return 0; - } + return v == 'N' || v == '"' || v == '0' || v == 'n' || v == 't' || v == 'f'; } /*--------------------------------------------------------------------*/ void @@ -163,6 +167,7 @@ jsonparse_next(struct jsonparse_state *state) char c; char s; char v; + bool ret; skip_ws(state); c = state->json[state->pos]; @@ -173,48 +178,51 @@ jsonparse_next(struct jsonparse_state *state) switch(c) { case '{': if((s == 0 && v == 0) || s == '[' || s == ':') { - push(state, c); - } else { - state->error = JSON_ERROR_UNEXPECTED_OBJECT; - return JSON_TYPE_ERROR; + if(push(state, c)) { + return c; + } } - return c; + state->error = JSON_ERROR_UNEXPECTED_OBJECT; + return JSON_TYPE_ERROR; case '}': if((s == ':' && v != ',' && v != 0 ) || (s == '{' && v == 0)) { - pop(state); - } else { - state->error = JSON_ERROR_UNEXPECTED_END_OF_OBJECT; - return JSON_TYPE_ERROR; + if(pop(state)) { + return c; + } } - return c; + state->error = JSON_ERROR_UNEXPECTED_END_OF_OBJECT; + return JSON_TYPE_ERROR; case ']': if(s == '[' && v != ',') { - pop(state); - } else { - state->error = JSON_ERROR_UNEXPECTED_END_OF_ARRAY; - return JSON_TYPE_ERROR; + if(pop(state)) { + return c; + } } - return c; + state->error = JSON_ERROR_UNEXPECTED_END_OF_ARRAY; + return JSON_TYPE_ERROR; case ':': if(s == '{' && v == 'N') { - modify(state, ':'); + ret = modify(state, ':'); state->vtype = 0; - } else { - state->error = JSON_ERROR_SYNTAX; - return JSON_TYPE_ERROR; + if(ret) { + return jsonparse_next(state); + } } - return jsonparse_next(state); + state->error = JSON_ERROR_SYNTAX; + return JSON_TYPE_ERROR; case ',': if(s == ':' && v != 0) { - modify(state, '{'); + ret = modify(state, '{'); state->vtype = c; + if(ret) { + return c; + } } else if(s == '[') { state->vtype = c; - } else { - state->error = JSON_ERROR_SYNTAX; - return JSON_TYPE_ERROR; + return c; } - return c; + state->error = JSON_ERROR_SYNTAX; + return JSON_TYPE_ERROR; case '"': if((s == 0 && v == 0) || s == '{' || s == '[' || s == ':') { return atomic(state, c = (s == '{' ? JSON_TYPE_PAIR_NAME : c)); @@ -225,12 +233,12 @@ jsonparse_next(struct jsonparse_state *state) return c; case '[': if((s == 0 && v == 0) || s == '[' || s == ':') { - push(state, c); - } else { - state->error = JSON_ERROR_UNEXPECTED_ARRAY; - return JSON_TYPE_ERROR; + if(push(state, c)) { + return c; + } } - return c; + state->error = JSON_ERROR_UNEXPECTED_ARRAY; + return JSON_TYPE_ERROR; case 0: if(v == 0 || state->depth > 0) { state->error = JSON_ERROR_SYNTAX; diff --git a/os/lib/json/jsontree.c b/os/lib/json/jsontree.c index 13d7d8604..259525376 100644 --- a/os/lib/json/jsontree.c +++ b/os/lib/json/jsontree.c @@ -198,7 +198,10 @@ jsontree_print_next(struct jsontree_context *js_ctx) } else { ov = o->values[index]; } - /* TODO check max depth */ + if(js_ctx->depth >= JSONTREE_MAX_DEPTH - 1) { + /* Too deep: return 0 */ + return 0; + } js_ctx->depth++; /* step down to value... */ js_ctx->index[js_ctx->depth] = 0; /* and init index */ js_ctx->values[js_ctx->depth] = ov; @@ -299,7 +302,10 @@ find_next(struct jsontree_context *js_ctx) } else { ov = o->values[index]; } - /* TODO check max depth */ + if(js_ctx->depth >= JSONTREE_MAX_DEPTH - 1) { + /* Too deep: return NULL */ + return NULL; + } js_ctx->depth++; /* step down to value... */ js_ctx->index[js_ctx->depth] = 0; /* and init index */ js_ctx->values[js_ctx->depth] = ov; diff --git a/os/net/ipv6/sicslowpan.c b/os/net/ipv6/sicslowpan.c index 35128c3d7..d61d44baf 100644 --- a/os/net/ipv6/sicslowpan.c +++ b/os/net/ipv6/sicslowpan.c @@ -126,24 +126,6 @@ /** @} */ - -/** \brief Maximum available size for frame headers, - link layer security-related overhead, as well as - 6LoWPAN payload. */ -#ifdef SICSLOWPAN_CONF_MAC_MAX_PAYLOAD -#define MAC_MAX_PAYLOAD SICSLOWPAN_CONF_MAC_MAX_PAYLOAD -#else /* SICSLOWPAN_CONF_MAC_MAX_PAYLOAD */ -#define MAC_MAX_PAYLOAD (127 - 2) -#endif /* SICSLOWPAN_CONF_MAC_MAX_PAYLOAD */ - -/** \brief Maximum size of a frame header. This value is - * used in case framer returns an error */ -#ifdef SICSLOWPAN_CONF_MAC_MAX_HEADER -#define MAC_MAX_HEADER SICSLOWPAN_CONF_MAC_MAX_HEADER -#else /* SICSLOWPAN_CONF_MAC_MAX_HEADER */ -#define MAC_MAX_HEADER 21 -#endif /* SICSLOWPAN_CONF_MAC_MAX_HEADER */ - /* set this to zero if not compressing EXT_HDR - for backwards compatibility */ #ifdef SICSLOWPAN_CONF_COMPRESS_EXT_HDR #define COMPRESS_EXT_HDR SICSLOWPAN_CONF_COMPRESS_EXT_HDR @@ -246,7 +228,7 @@ static uint16_t my_tag; #define SICSLOWPAN_FRAGMENT_SIZE SICSLOWPAN_CONF_FRAGMENT_SIZE #else /* The default fragment size (110 bytes for 127-2 bytes frames) */ -#define SICSLOWPAN_FRAGMENT_SIZE (MAC_MAX_PAYLOAD - 15) +#define SICSLOWPAN_FRAGMENT_SIZE (127 - 2 - 15) #endif /* Assuming that the worst growth for uncompression is 38 bytes */ @@ -1544,8 +1526,6 @@ fragment_copy_payload_and_send(uint16_t uip_offset, linkaddr_t *dest) { static uint8_t output(const linkaddr_t *localdest) { - int framer_hdrlen; - int max_payload; int frag_needed; /* The MAC address of the destination of the packet */ @@ -1584,13 +1564,23 @@ output(const linkaddr_t *localdest) /* Calculate NETSTACK_FRAMER's header length, that will be added in the NETSTACK_MAC */ packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &dest); - framer_hdrlen = NETSTACK_FRAMER.length(); - if(framer_hdrlen < 0) { - /* Framing failed, we assume the maximum header length */ - framer_hdrlen = MAC_MAX_HEADER; - } +#if LLSEC802154_USES_AUX_HEADER + /* copy LLSEC level */ + packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, + uipbuf_get_attr(UIPBUF_ATTR_LLSEC_LEVEL)); +#if LLSEC802154_USES_EXPLICIT_KEYS + packetbuf_set_attr(PACKETBUF_ATTR_KEY_INDEX, + uipbuf_get_attr(UIPBUF_ATTR_LLSEC_KEY_ID)); +#endif /* LLSEC802154_USES_EXPLICIT_KEYS */ +#endif /* LLSEC802154_USES_AUX_HEADER */ - mac_max_payload = MAC_MAX_PAYLOAD - framer_hdrlen; + mac_max_payload = NETSTACK_MAC.max_payload(); + + if(mac_max_payload <= 0) { + /* Framing failed, drop packet */ + LOG_WARN("output: failed to calculate payload size - dropping packet\n"); + return 0; + } /* Try to compress the headers */ #if SICSLOWPAN_COMPRESSION == SICSLOWPAN_COMPRESSION_IPV6 @@ -1611,22 +1601,17 @@ output(const linkaddr_t *localdest) } #endif /* SICSLOWPAN_COMPRESSION >= SICSLOWPAN_COMPRESSION_IPHC */ - /* Calculate NETSTACK_FRAMER's header length, that will be added in the NETSTACK_MAC. - * We calculate it here only to make a better decision of whether the outgoing packet - * needs to be fragmented or not. */ - packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &dest); - framer_hdrlen = NETSTACK_FRAMER.length(); - if(framer_hdrlen < 0) { - /* Framing failed, we assume the maximum header length */ - framer_hdrlen = MAC_MAX_HEADER; - } + /* Use the mac_max_payload to understand what is the max payload in a MAC + * packet. We calculate it here only to make a better decision of whether + * the outgoing packet needs to be fragmented or not. */ - max_payload = MAC_MAX_PAYLOAD - framer_hdrlen; - frag_needed = (int)uip_len - (int)uncomp_hdr_len + (int)packetbuf_hdr_len > max_payload; + packetbuf_set_addr(PACKETBUF_ADDR_RECEIVER, &dest); + + frag_needed = (int)uip_len - (int)uncomp_hdr_len + (int)packetbuf_hdr_len > mac_max_payload; LOG_INFO("output: header len %d -> %d, total len %d -> %d, MAC max payload %d, frag_needed %d\n", uncomp_hdr_len, packetbuf_hdr_len, uip_len, uip_len - uncomp_hdr_len + packetbuf_hdr_len, - max_payload, frag_needed); + mac_max_payload, frag_needed); if(frag_needed) { #if SICSLOWPAN_CONF_FRAG @@ -1646,11 +1631,11 @@ output(const linkaddr_t *localdest) /* Total IPv6 payload */ int total_payload = (uip_len - uncomp_hdr_len); /* IPv6 payload that goes to first fragment */ - int frag1_payload = (max_payload - packetbuf_hdr_len - SICSLOWPAN_FRAG1_HDR_LEN) & 0xfffffff8; + int frag1_payload = (mac_max_payload - packetbuf_hdr_len - SICSLOWPAN_FRAG1_HDR_LEN) & 0xfffffff8; /* max IPv6 payload in each FRAGN. Must be multiple of 8 bytes */ - int fragn_max_payload = (max_payload - SICSLOWPAN_FRAGN_HDR_LEN) & 0xfffffff8; + int fragn_max_payload = (mac_max_payload - SICSLOWPAN_FRAGN_HDR_LEN) & 0xfffffff8; /* max IPv6 payload in the last fragment. Needs not be multiple of 8 bytes */ - int last_fragn_max_payload = max_payload - SICSLOWPAN_FRAGN_HDR_LEN; + int last_fragn_max_payload = mac_max_payload - SICSLOWPAN_FRAGN_HDR_LEN; /* sum of all IPv6 payload that goes to non-first and non-last fragments */ int middle_fragn_total_payload = MAX(total_payload - frag1_payload - last_fragn_max_payload, 0); /* Ceiling of: 2 + middle_fragn_total_payload / fragn_max_payload */ @@ -1802,6 +1787,9 @@ input(void) return; } + /* Clear uipbuf and set default attributes */ + uipbuf_clear(); + /* This is default uip_buf since we assume that this is not fragmented */ buffer = (uint8_t *)UIP_IP_BUF; @@ -1836,7 +1824,6 @@ input(void) } buffer = frag_info[frag_context].first_frag; - break; case SICSLOWPAN_DISPATCH_FRAGN: /* @@ -2000,6 +1987,19 @@ input(void) callback->input_callback(); } +#if LLSEC802154_USES_AUX_HEADER + /* + * Assuming that the last packet in packetbuf is containing + * the LLSEC state so that it can be copied to uipbuf. + */ + uipbuf_set_attr(UIPBUF_ATTR_LLSEC_LEVEL, + packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL)); +#if LLSEC802154_USES_EXPLICIT_KEYS + uipbuf_set_attr(UIPBUF_ATTR_LLSEC_KEY_ID, + packetbuf_attr(PACKETBUF_ATTR_KEY_INDEX)); +#endif /* LLSEC802154_USES_EXPLICIT_KEYS */ +#endif /* LLSEC802154_USES_AUX_HEADER */ + tcpip_input(); #if SICSLOWPAN_CONF_FRAG } diff --git a/os/net/ipv6/uip6.c b/os/net/ipv6/uip6.c index 25e052f34..8a1c27682 100644 --- a/os/net/ipv6/uip6.c +++ b/os/net/ipv6/uip6.c @@ -388,6 +388,7 @@ uip_init(void) { int c; + uipbuf_init(); uip_ds6_init(); uip_icmp6_init(); uip_nd6_init(); diff --git a/os/net/ipv6/uipbuf.c b/os/net/ipv6/uipbuf.c index eaf43e308..f7e8f4b06 100644 --- a/os/net/ipv6/uipbuf.c +++ b/os/net/ipv6/uipbuf.c @@ -37,6 +37,7 @@ /*---------------------------------------------------------------------------*/ static uint16_t uipbuf_attrs[UIPBUF_ATTR_MAX]; +static uint16_t uipbuf_default_attrs[UIPBUF_ATTR_MAX]; /*---------------------------------------------------------------------------*/ void @@ -197,15 +198,21 @@ uipbuf_set_attr(uint8_t type, uint16_t value) return 0; } /*---------------------------------------------------------------------------*/ +int +uipbuf_set_default_attr(uint8_t type, uint16_t value) +{ + if(type < UIPBUF_ATTR_MAX) { + uipbuf_default_attrs[type] = value; + return 1; + } + return 0; +} +/*---------------------------------------------------------------------------*/ void uipbuf_clear_attr(void) { - /* set everything to "zero" */ - memset(uipbuf_attrs, 0, sizeof(uipbuf_attrs)); - - /* And initialize anything that should be initialized */ - uipbuf_set_attr(UIPBUF_ATTR_MAX_MAC_TRANSMISSIONS, - UIP_MAX_MAC_TRANSMISSIONS_UNDEFINED); + /* set everything to "defaults" */ + memcpy(uipbuf_attrs, uipbuf_default_attrs, sizeof(uipbuf_attrs)); } /*---------------------------------------------------------------------------*/ void @@ -227,3 +234,17 @@ uipbuf_is_attr_flag(uint16_t flag) return (uipbuf_attrs[UIPBUF_ATTR_FLAGS] & flag) == flag; } /*---------------------------------------------------------------------------*/ +void +uipbuf_init(void) +{ + memset(uipbuf_default_attrs, 0, sizeof(uipbuf_default_attrs)); + /* And initialize anything that should be initialized */ + uipbuf_set_default_attr(UIPBUF_ATTR_MAX_MAC_TRANSMISSIONS, + UIP_MAX_MAC_TRANSMISSIONS_UNDEFINED); + /* set the not-set default value - this will cause the MAC layer to + configure its default */ + uipbuf_set_default_attr(UIPBUF_ATTR_LLSEC_LEVEL, + UIPBUF_ATTR_LLSEC_LEVEL_MAC_DEFAULT); +} + +/*---------------------------------------------------------------------------*/ diff --git a/os/net/ipv6/uipbuf.h b/os/net/ipv6/uipbuf.h index 96b180ee8..fdea60b28 100644 --- a/os/net/ipv6/uipbuf.h +++ b/os/net/ipv6/uipbuf.h @@ -125,6 +125,17 @@ uint16_t uipbuf_get_attr(uint8_t type); */ int uipbuf_set_attr(uint8_t type, uint16_t value); +/** + * \brief Set the default value of the attribute + * \param type The attribute to set the default value of + * \param value The value to set + * \retval 0 - indicates failure of setting the value + * \retval 1 - indicates success of setting the value + * + * This function sets the default value of a uipbuf attribute. + */ +int uipbuf_set_default_attr(uint8_t type, uint16_t value); + /** * \brief Set bits in the uipbuf attribute flags. * \param flag_bits The bits to set in the flag. @@ -159,6 +170,14 @@ uint16_t uipbuf_is_attr_flag(uint16_t flag_bits); */ void uipbuf_clear_attr(void); +/** + * \brief Initialize uipbuf attributes. + * + * This function initialize all attributes in the uipbuf + * attributes including all flags. + */ +void uipbuf_init(void); + /** * \brief The bits defined for uipbuf attributes flag. * @@ -168,6 +187,9 @@ void uipbuf_clear_attr(void); /* Avoid using prefix compression on the packet (6LoWPAN) */ #define UIPBUF_ATTR_FLAGS_6LOWPAN_NO_PREFIX_COMPRESSION 0x02 +/* MAC will set the default for this packet */ +#define UIPBUF_ATTR_LLSEC_LEVEL_MAC_DEFAULT 0xffff + /** * \brief The attributes defined for uipbuf attributes function. * diff --git a/os/net/mac/ble/ble-l2cap.c b/os/net/mac/ble/ble-l2cap.c index 076d919e8..fb755cc85 100644 --- a/os/net/mac/ble/ble-l2cap.c +++ b/os/net/mac/ble/ble-l2cap.c @@ -505,6 +505,12 @@ off(void) return 0; } /*---------------------------------------------------------------------------*/ +static int +max_payload(void) +{ + return BLE_L2CAP_NODE_MTU; +} +/*---------------------------------------------------------------------------*/ const struct mac_driver ble_l2cap_driver = { "ble-l2cap", init, @@ -512,6 +518,7 @@ const struct mac_driver ble_l2cap_driver = { input, on, off, + max_payload, }; /*---------------------------------------------------------------------------*/ PROCESS_THREAD(ble_l2cap_tx_process, ev, data) diff --git a/os/net/mac/csma/anti-replay.c b/os/net/mac/csma/anti-replay.c new file mode 100644 index 000000000..347674184 --- /dev/null +++ b/os/net/mac/csma/anti-replay.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2014, Hasso-Plattner-Institut. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +/** + * \file + * Protects against replay attacks by comparing with the last + * unicast or broadcast frame counter of the sender. + * \author + * Konrad Krentz + */ + +/** + * \addtogroup csma + * @{ + */ + +#include "net/mac/csma/anti-replay.h" +#include "net/packetbuf.h" +#include "net/mac/llsec802154.h" + +#if LLSEC802154_USES_FRAME_COUNTER + +/* This node's current frame counter value */ +static uint32_t counter; + +/*---------------------------------------------------------------------------*/ +void +anti_replay_set_counter(void) +{ + frame802154_frame_counter_t reordered_counter; + + ++counter; + reordered_counter.u32 = LLSEC802154_HTONL(counter); + + packetbuf_set_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1, reordered_counter.u16[0]); + packetbuf_set_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3, reordered_counter.u16[1]); +} +/*---------------------------------------------------------------------------*/ +uint32_t +anti_replay_get_counter(void) +{ + frame802154_frame_counter_t disordered_counter; + + disordered_counter.u16[0] = packetbuf_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1); + disordered_counter.u16[1] = packetbuf_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3); + + return LLSEC802154_HTONL(disordered_counter.u32); +} +/*---------------------------------------------------------------------------*/ +void +anti_replay_init_info(struct anti_replay_info *info) +{ + info->last_broadcast_counter + = info->last_unicast_counter + = anti_replay_get_counter(); +} +/*---------------------------------------------------------------------------*/ +int +anti_replay_was_replayed(struct anti_replay_info *info) +{ + uint32_t received_counter; + + received_counter = anti_replay_get_counter(); + + if(packetbuf_holds_broadcast()) { + /* broadcast */ + if(received_counter <= info->last_broadcast_counter) { + return 1; + } else { + info->last_broadcast_counter = received_counter; + return 0; + } + } else { + /* unicast */ + if(received_counter <= info->last_unicast_counter) { + return 1; + } else { + info->last_unicast_counter = received_counter; + return 0; + } + } +} +/*---------------------------------------------------------------------------*/ +#endif /* LLSEC802154_USES_FRAME_COUNTER */ + +/** @} */ diff --git a/os/net/mac/csma/anti-replay.h b/os/net/mac/csma/anti-replay.h new file mode 100644 index 000000000..9211a6e7a --- /dev/null +++ b/os/net/mac/csma/anti-replay.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2014, Hasso-Plattner-Institut. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +/** + * \file + * Interface to anti-replay mechanisms. + * \author + * Konrad Krentz + */ + +/** + * \addtogroup llsec802154 + * @{ + */ + +#ifndef ANTI_REPLAY_H +#define ANTI_REPLAY_H + +#include "contiki.h" + +struct anti_replay_info { + uint32_t last_broadcast_counter; + uint32_t last_unicast_counter; +}; + +/** + * \brief Sets the frame counter packetbuf attributes. + */ +void anti_replay_set_counter(void); + +/** + * \brief Gets the frame counter from packetbuf. + */ +uint32_t anti_replay_get_counter(void); + +/** + * \brief Initializes the anti-replay information about the sender + * \param info Anti-replay information about the sender + */ +void anti_replay_init_info(struct anti_replay_info *info); + +/** + * \brief Checks if received frame was replayed + * \param info Anti-replay information about the sender + * \retval 0 <-> received frame was not replayed + */ +int anti_replay_was_replayed(struct anti_replay_info *info); + +#endif /* ANTI_REPLAY_H */ + +/** @} */ diff --git a/os/net/mac/csma/ccm-star-packetbuf.c b/os/net/mac/csma/ccm-star-packetbuf.c new file mode 100644 index 000000000..17b9befdc --- /dev/null +++ b/os/net/mac/csma/ccm-star-packetbuf.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2013, Hasso-Plattner-Institut. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +/** + * \file + * CCM* convenience functions for LLSEC use + * \author + * Justin King-Lacroix + * Konrad Krentz + */ + +#include "net/linkaddr.h" +#include "net/packetbuf.h" +#include "net/mac/llsec802154.h" +#include + +#if LLSEC802154_USES_AUX_HEADER && LLSEC802154_USES_FRAME_COUNTER + +/*---------------------------------------------------------------------------*/ +static const uint8_t * +get_extended_address(const linkaddr_t *addr) +#if LINKADDR_SIZE == 2 +{ + /* workaround for short addresses: derive EUI64 as in RFC 6282 */ + static linkaddr_extended_t template = { { 0x00 , 0x00 , 0x00 , + 0xFF , 0xFE , 0x00 , 0x00 , 0x00 } }; + template.u16[3] = LLSEC802154_HTONS(addr->u16); + + return template.u8; +} +#else /* LINKADDR_SIZE == 2 */ +{ + return addr->u8; +} +#endif /* LINKADDR_SIZE == 2 */ +/*---------------------------------------------------------------------------*/ +void +ccm_star_packetbuf_set_nonce(uint8_t *nonce, int forward) +{ + const linkaddr_t *source_addr; + + source_addr = forward ? &linkaddr_node_addr : packetbuf_addr(PACKETBUF_ADDR_SENDER); + memcpy(nonce, get_extended_address(source_addr), 8); + nonce[8] = packetbuf_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3) >> 8; + nonce[9] = packetbuf_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3) & 0xff; + nonce[10] = packetbuf_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1) >> 8; + nonce[11] = packetbuf_attr(PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1) & 0xff; + nonce[12] = packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL); +} +/*---------------------------------------------------------------------------*/ +#endif /* LLSEC802154_USES_AUX_HEADER && LLSEC802154_USES_FRAME_COUNTER */ diff --git a/os/net/mac/csma/ccm-star-packetbuf.h b/os/net/mac/csma/ccm-star-packetbuf.h new file mode 100644 index 000000000..578bdef96 --- /dev/null +++ b/os/net/mac/csma/ccm-star-packetbuf.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013, Hasso-Plattner-Institut. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +#ifndef CCM_STAR_PACKETBUF_H_ +#define CCM_STAR_PACKETBUF_H_ + +/*---------------------------------------------------------------------------*/ +void ccm_star_packetbuf_set_nonce(uint8_t *nonce, int forward); + +#endif /* CCM_STAR_PACKETBUF_H_ */ diff --git a/os/net/mac/csma/csma-output.c b/os/net/mac/csma/csma-output.c index 366840455..653743967 100644 --- a/os/net/mac/csma/csma-output.c +++ b/os/net/mac/csma/csma-output.c @@ -40,6 +40,7 @@ */ #include "net/mac/csma/csma.h" +#include "net/mac/csma/csma-security.h" #include "net/packetbuf.h" #include "net/queuebuf.h" #include "dev/watchdog.h" @@ -173,9 +174,16 @@ send_one_packet(struct neighbor_queue *n, struct packet_queue *q) packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr); packetbuf_set_attr(PACKETBUF_ATTR_MAC_ACK, 1); - if(NETSTACK_FRAMER.create() < 0) { +#if LLSEC802154_ENABLED +#if LLSEC802154_USES_EXPLICIT_KEYS + /* This should possibly be taken from upper layers in the future */ + packetbuf_set_attr(PACKETBUF_ATTR_KEY_ID_MODE, CSMA_LLSEC_KEY_ID_MODE); +#endif /* LLSEC802154_USES_EXPLICIT_KEYS */ +#endif /* LLSEC802154_ENABLED */ + + if(csma_security_create_frame() < 0) { /* Failed to allocate space for headers */ - LOG_ERR("failed to create packet\n"); + LOG_ERR("failed to create packet, seqno: %d\n", packetbuf_attr(PACKETBUF_ATTR_MAC_SEQNO)); ret = MAC_TX_ERR_FATAL; } else { int is_broadcast; diff --git a/os/net/mac/csma/csma-security.c b/os/net/mac/csma/csma-security.c new file mode 100644 index 000000000..0b44fa348 --- /dev/null +++ b/os/net/mac/csma/csma-security.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2017, RISE SICS + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +/** + * \file + * CSMA security + * \author + * Joakim Eriksson + */ + +/** + * \addtogroup csma + * @{ +*/ + +#include "contiki.h" +#include "net/mac/csma/csma.h" +#include "net/mac/csma/anti-replay.h" +#include "net/mac/csma/csma-security.h" +#include "net/mac/framer/frame802154.h" +#include "net/mac/framer/framer-802154.h" +#include "net/mac/llsec802154.h" +#include "net/netstack.h" +#include "net/packetbuf.h" +#include "lib/ccm-star.h" +#include "lib/aes-128.h" +#include +#include +#include "ccm-star-packetbuf.h" +/* Log configuration */ +#include "sys/log.h" +#define LOG_MODULE "CSMA" +#define LOG_LEVEL LOG_LEVEL_MAC + +#if LOG_LEVEL == LOG_LEVEL_DBG +static const char * HEX = "0123456789ABCDEF"; +#endif + +#if LLSEC802154_USES_AUX_HEADER && LLSEC802154_USES_FRAME_COUNTER + +#define MIC_LEN(level) LLSEC802154_MIC_LEN(level) + +#if LLSEC802154_USES_EXPLICIT_KEYS +#define LLSEC_KEY_INDEX (FRAME802154_IMPLICIT_KEY == packetbuf_attr(PACKETBUF_ATTR_KEY_ID_MODE) \ + ? 0 \ + : packetbuf_attr(PACKETBUF_ATTR_KEY_INDEX)) +#define LLSEC_KEY_MODE (packetbuf_attr(PACKETBUF_ATTR_KEY_ID_MODE)) +#else +#define LLSEC_KEY_INDEX (0) +#define LLSEC_KEY_MODE (FRAME802154_IMPLICIT_KEY) +#endif /* LLSEC802154_USES_EXPLICIT_KEYS */ + +/** + * The keys for LLSEC for CSMA + */ +typedef struct { + uint8_t u8[16]; +} aes_key_t; +static aes_key_t keys[CSMA_LLSEC_MAXKEYS]; + +/* assumed to be 16 bytes */ +int +csma_security_set_key(uint8_t index, const uint8_t *key) +{ + if(key != NULL && index < CSMA_LLSEC_MAXKEYS) { + memcpy(keys[index].u8, key, 16); + return 1; + } + return 0; +} + +#define N_KEYS (sizeof(keys) / sizeof(aes_key)) +/*---------------------------------------------------------------------------*/ +static int +aead(uint8_t hdrlen, int forward) +{ + uint8_t totlen; + uint8_t nonce[CCM_STAR_NONCE_LENGTH]; + uint8_t *m; + uint8_t m_len; + uint8_t *a; + uint8_t a_len; + uint8_t *result; + /* Allocate for MAX level */ + uint8_t generated_mic[MIC_LEN(7)]; + uint8_t *mic; + uint8_t key_index; + aes_key_t *key; + uint8_t with_encryption; + + key_index = LLSEC_KEY_INDEX; + if(key_index >= CSMA_LLSEC_MAXKEYS) { + LOG_ERR("Key not available: %u\n", key_index); + return 0; + } + + key = &keys[key_index]; + + ccm_star_packetbuf_set_nonce(nonce, forward); + totlen = packetbuf_totlen(); + a = packetbuf_hdrptr(); + + with_encryption = + (packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x4) ? 1 : 0; + + if(with_encryption) { + a_len = hdrlen; + m = a + a_len; + m_len = totlen - hdrlen; + } else { + a_len = totlen; + m = NULL; + m_len = 0; + } + + mic = a + totlen; + result = forward ? mic : generated_mic; + + CCM_STAR.set_key(key->u8); + CCM_STAR.aead(nonce, + m, m_len, + a, a_len, + result, MIC_LEN(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x07), + forward); + + if(forward) { + packetbuf_set_datalen(packetbuf_datalen() + MIC_LEN(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x07)); + return 1; + } else { + return (memcmp(generated_mic, mic, MIC_LEN(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x07)) == 0); + } +} + +/*---------------------------------------------------------------------------*/ +int +csma_security_create_frame(void) +{ + int hdr_len; + + packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME); + if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) > 0 && + LLSEC_KEY_INDEX != 0xffff) { + anti_replay_set_counter(); + } + + hdr_len = NETSTACK_FRAMER.create(); + if(hdr_len < 0) { + return hdr_len; + } + + if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) > 0) { +#if LOG_LEVEL == LOG_LEVEL_DBG + int i = 0; + uint8_t *p; + LOG_DBG(" Payload before (%d):", packetbuf_totlen()); + p = packetbuf_hdrptr(); + for(i = 0; i < packetbuf_totlen(); i++) { + LOG_DBG_("%c%c", HEX[(p[i] >> 4) & 0x0f], HEX[p[i] & 0x0f]); + } + LOG_DBG("\n"); +#endif + + if(!aead(hdr_len, 1)) { + LOG_ERR("failed to encrypt packet to "); + LOG_ERR_LLADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER)); + LOG_ERR_("\n"); + return FRAMER_FAILED; + } + LOG_INFO("LLSEC-OUT:"); + LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER)); + LOG_INFO_(" "); + LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER)); + LOG_INFO_(" %u (%u) LV:%d, KEY:0x%02x\n", packetbuf_datalen(), packetbuf_totlen(), + packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL), LLSEC_KEY_INDEX); + +#if LOG_LEVEL == LOG_LEVEL_DBG + LOG_DBG(" Payload after: (%d)", packetbuf_totlen()); + p = packetbuf_hdrptr(); + for(i = 0; i < packetbuf_totlen(); i++) { + LOG_DBG_("%c%c", HEX[(p[i] >> 4) & 0x0f], HEX[p[i] & 0x0f]); + } + LOG_DBG_("\n"); +#endif + + } + return hdr_len; +} + +/*---------------------------------------------------------------------------*/ +int +csma_security_frame_len(void) +{ + if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) > 0 && + LLSEC_KEY_INDEX != 0xffff) { + return NETSTACK_FRAMER.length() + + MIC_LEN(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x07); + } + return NETSTACK_FRAMER.length(); +} +/*---------------------------------------------------------------------------*/ +int +csma_security_parse_frame(void) +{ + int hdr_len; + + hdr_len = NETSTACK_FRAMER.parse(); + if(hdr_len < 0) { + return hdr_len; + } + + if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) == 0) { + /* No security - no more processing required */ + return hdr_len; + } + + LOG_INFO("LLSEC-IN: "); + LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER)); + LOG_INFO_(" "); + LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_RECEIVER)); + LOG_INFO_(" %d %u (%u) LV:%d KM:%d KEY:0x%02x\n", hdr_len, packetbuf_datalen(), + packetbuf_totlen(), packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL), + LLSEC_KEY_MODE, + LLSEC_KEY_INDEX); + + if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) != CSMA_LLSEC_SECURITY_LEVEL) { + LOG_INFO("received frame with wrong security level (%u) from ", + packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL)); + LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER)); + LOG_INFO_("\n"); + return FRAMER_FAILED; + } + + if(LLSEC_KEY_MODE != CSMA_LLSEC_KEY_ID_MODE) { + LOG_INFO("received frame with wrong key id mode (%u) from ", LLSEC_KEY_MODE); + LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER)); + LOG_INFO("\n"); + return FRAMER_FAILED; + } + + if(linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_SENDER), &linkaddr_node_addr)) { + LOG_INFO("frame from ourselves\n"); + return FRAMER_FAILED; + } + + if(packetbuf_datalen() <= MIC_LEN(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x07)) { + LOG_ERR("MIC error - too little data in frame!\n"); + return FRAMER_FAILED; + } + + packetbuf_set_datalen(packetbuf_datalen() - MIC_LEN(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) & 0x07)); + if(!aead(hdr_len, 0)) { + LOG_INFO("received unauthentic frame %u from ", + (unsigned int) anti_replay_get_counter()); + LOG_INFO_LLADDR(packetbuf_addr(PACKETBUF_ADDR_SENDER)); + LOG_INFO_("\n"); + return FRAMER_FAILED; + } + + /* TODO anti-reply protection */ + return hdr_len; +} +/*---------------------------------------------------------------------------*/ +#else +/* The "unsecure" version of the create frame / parse frame */ +int +csma_security_create_frame(void) +{ + packetbuf_set_attr(PACKETBUF_ATTR_FRAME_TYPE, FRAME802154_DATAFRAME); + return NETSTACK_FRAMER.create(); +} +int +csma_security_parse_frame(void) +{ + return NETSTACK_FRAMER.parse(); +} + +#endif /* LLSEC802154_USES_AUX_HEADER && LLSEC802154_USES_FRAME_COUNTER */ + +/** @} */ diff --git a/os/net/mac/csma/csma-security.h b/os/net/mac/csma/csma-security.h new file mode 100644 index 000000000..97092b84d --- /dev/null +++ b/os/net/mac/csma/csma-security.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2018, Tiny Mesh AS + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +/** + * \file + * LLSEC802154 Security related configuration + * \author + * Olav Frengstad + */ + +#ifndef CSMA_SECURITY_H_ +#define CSMA_SECURITY_H_ + + +#ifdef CSMA_CONF_LLSEC_DEFAULT_KEY0 +#define CSMA_LLSEC_DEFAULT_KEY0 CSMA_CONF_LLSEC_DEFAULT_KEY0 +#else +#define CSMA_LLSEC_DEFAULT_KEY0 {0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f} +#endif + +#ifdef CSMA_CONF_LLSEC_SECURITY_LEVEL +#define CSMA_LLSEC_SECURITY_LEVEL CSMA_CONF_LLSEC_SECURITY_LEVEL +#else +#define CSMA_LLSEC_SECURITY_LEVEL 5 +#endif /* CSMA_CONF_LLSEC_SECURITY_LEVEL */ + +#ifdef CSMA_CONF_LLSEC_KEY_ID_MODE +#define CSMA_LLSEC_KEY_ID_MODE CSMA_CONF_LLSEC_KEY_ID_MODE +#else +#define CSMA_LLSEC_KEY_ID_MODE FRAME802154_IMPLICIT_KEY +#endif /* CSMA_CONF_LLSEC_KEY_ID_MODE */ + +#ifdef CSMA_CONF_LLSEC_KEY_INDEX +#define CSMA_LLSEC_KEY_INDEX CSMA_CONF_LLSEC_KEY_INDEX +#else +#define CSMA_LLSEC_KEY_INDEX 0 +#endif /* CSMA_CONF_LLSEC_KEY_INDEX */ + +#ifdef CSMA_CONF_LLSEC_MAXKEYS +#define CSMA_LLSEC_MAXKEYS CSMA_CONF_LLSEC_MAXKEYS +#else +#define CSMA_LLSEC_MAXKEYS 1 +#endif + +#endif /* CSMA_SECURITY_H_ */ diff --git a/os/net/mac/csma/csma.c b/os/net/mac/csma/csma.c index 27b720395..87aa6a1af 100644 --- a/os/net/mac/csma/csma.c +++ b/os/net/mac/csma/csma.c @@ -49,10 +49,25 @@ #define LOG_MODULE "CSMA" #define LOG_LEVEL LOG_LEVEL_MAC + +static void +init_sec(void) +{ +#if LLSEC802154_USES_AUX_HEADER + if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) == + PACKETBUF_ATTR_SECURITY_LEVEL_DEFAULT) { + packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, + CSMA_LLSEC_SECURITY_LEVEL); + } +#endif +} /*---------------------------------------------------------------------------*/ static void send_packet(mac_callback_t sent, void *ptr) { + + init_sec(); + csma_output_packet(sent, ptr); } /*---------------------------------------------------------------------------*/ @@ -66,7 +81,7 @@ input_packet(void) if(packetbuf_datalen() == CSMA_ACK_LEN) { /* Ignore ack packets */ LOG_DBG("ignored ack\n"); - } else if(NETSTACK_FRAMER.parse() < 0) { + } else if(csma_security_parse_frame() < 0) { LOG_ERR("failed to parse %u\n", packetbuf_datalen()); } else if(!linkaddr_cmp(packetbuf_addr(PACKETBUF_ADDR_RECEIVER), &linkaddr_node_addr) && @@ -120,16 +135,41 @@ off(void) static void init(void) { + +#if LLSEC802154_USES_AUX_HEADER +#ifdef CSMA_LLSEC_DEFAULT_KEY0 + uint8_t key[16] = CSMA_LLSEC_DEFAULT_KEY0; + csma_security_set_key(0, key); +#endif +#endif /* LLSEC802154_USES_AUX_HEADER */ csma_output_init(); on(); } /*---------------------------------------------------------------------------*/ +static int +max_payload(void) +{ + int framer_hdrlen; + + init_sec(); + + framer_hdrlen = NETSTACK_FRAMER.length(); + + if(framer_hdrlen < 0) { + /* Framing failed, we assume the maximum header length */ + framer_hdrlen = CSMA_MAC_MAX_HEADER; + } + + return CSMA_MAC_LEN - framer_hdrlen; +} +/*---------------------------------------------------------------------------*/ const struct mac_driver csma_driver = { "CSMA", init, send_packet, input_packet, on, - off + off, + max_payload, }; /*---------------------------------------------------------------------------*/ diff --git a/os/net/mac/csma/csma.h b/os/net/mac/csma/csma.h index 9e0773f28..88396db0b 100644 --- a/os/net/mac/csma/csma.h +++ b/os/net/mac/csma/csma.h @@ -65,6 +65,25 @@ #define CSMA_ACK_LEN 3 +/* Default MAC len for 802.15.4 classic */ +#ifdef CSMA_MAC_CONF_LEN +#define CSMA_MAC_LEN CSMA_MAC_CONF_LEN +#else +#define CSMA_MAC_LEN 127 - 2 +#endif + +/* just a default - with LLSEC, etc */ +#define CSMA_MAC_MAX_HEADER 21 + + extern const struct mac_driver csma_driver; +/* CSMA security framer functions */ +int csma_security_create_frame(void); +int csma_security_parse_frame(void); + +/* key management for CSMA */ +int csma_security_set_key(uint8_t index, const uint8_t *key); + + #endif /* CSMA_H_ */ diff --git a/os/net/mac/llsec802154.h b/os/net/mac/llsec802154.h index fe1a9d231..e808fef7a 100644 --- a/os/net/mac/llsec802154.h +++ b/os/net/mac/llsec802154.h @@ -74,6 +74,12 @@ #define LLSEC802154_USES_AUX_HEADER LLSEC802154_ENABLED #endif /* LLSEC802154_CONF_USES_AUX_HEADER */ +#ifdef LLSEC802154_CONF_USES_FRAME_COUNTER +#define LLSEC802154_USES_FRAME_COUNTER LLSEC802154_CONF_USES_FRAME_COUNTER +#else +#define LLSEC802154_USES_FRAME_COUNTER LLSEC802154_ENABLED +#endif /* LLSEC802154_CONF_USES_FRAME_COUNTER */ + #if UIP_BYTE_ORDER == UIP_LITTLE_ENDIAN #define LLSEC802154_HTONS(n) (n) #define LLSEC802154_HTONL(n) (n) diff --git a/os/net/mac/mac.h b/os/net/mac/mac.h index 4f2a75b15..f64838b4c 100644 --- a/os/net/mac/mac.h +++ b/os/net/mac/mac.h @@ -76,6 +76,9 @@ struct mac_driver { /** Turn the MAC layer off. */ int (* off)(void); + + /** Read out estimated max payload size based on payload in packetbuf */ + int (* max_payload)(void); }; /* Generic MAC return values. */ diff --git a/os/net/mac/nullmac/nullmac.c b/os/net/mac/nullmac/nullmac.c index a6199a3f9..de92ee5d8 100644 --- a/os/net/mac/nullmac/nullmac.c +++ b/os/net/mac/nullmac/nullmac.c @@ -67,6 +67,12 @@ off(void) return 0; } /*---------------------------------------------------------------------------*/ +static int +max_payload(void) +{ + return 0; +} +/*---------------------------------------------------------------------------*/ static void init(void) { @@ -78,6 +84,7 @@ const struct mac_driver nullmac_driver = { send_packet, packet_input, on, - off + off, + max_payload, }; /*---------------------------------------------------------------------------*/ diff --git a/os/net/mac/tsch/tsch-const.h b/os/net/mac/tsch/tsch-const.h index d158c802c..c4712ce2d 100644 --- a/os/net/mac/tsch/tsch-const.h +++ b/os/net/mac/tsch/tsch-const.h @@ -66,8 +66,8 @@ /* 1 channel, sequence length 1 */ #define TSCH_HOPPING_SEQUENCE_1_1 (uint8_t[]){ 20 } -/* Max TSCH packet lenght */ -#define TSCH_PACKET_MAX_LEN MIN(127, PACKETBUF_SIZE) +/* Max TSCH packet lenght - last bytes are CRC in default 802.15.4 packets */ +#define TSCH_PACKET_MAX_LEN MIN(127 - 2, PACKETBUF_SIZE) /* The jitter to remove in ticks. * This should be the sum of measurement errors on Tx and Rx nodes. diff --git a/os/net/mac/tsch/tsch.c b/os/net/mac/tsch/tsch.c index 8a5218355..a33feeef1 100644 --- a/os/net/mac/tsch/tsch.c +++ b/os/net/mac/tsch/tsch.c @@ -1151,13 +1151,21 @@ turn_off(void) return 1; } /*---------------------------------------------------------------------------*/ +static int +max_payload(void) +{ + /* Setup security... before. */ + return TSCH_PACKET_MAX_LEN - NETSTACK_FRAMER.length(); +} +/*---------------------------------------------------------------------------*/ const struct mac_driver tschmac_driver = { "TSCH", tsch_init, send_packet, packet_input, turn_on, - turn_off + turn_off, + max_payload, }; /*---------------------------------------------------------------------------*/ /** @} */ diff --git a/os/net/packetbuf.h b/os/net/packetbuf.h index 20e071474..c077ae940 100644 --- a/os/net/packetbuf.h +++ b/os/net/packetbuf.h @@ -55,6 +55,7 @@ #include "contiki.h" #include "net/linkaddr.h" #include "net/mac/llsec802154.h" +#include "net/mac/csma/csma-security.h" #include "net/mac/tsch/tsch-conf.h" /** @@ -238,6 +239,11 @@ enum { PACKETBUF_ATTR_KEY_INDEX, #endif /* LLSEC802154_USES_EXPLICIT_KEYS */ +#if LLSEC802154_USES_FRAME_COUNTER + PACKETBUF_ATTR_FRAME_COUNTER_BYTES_0_1, + PACKETBUF_ATTR_FRAME_COUNTER_BYTES_2_3, +#endif /* LLSEC802154_USES_FRAME_COUNTER */ + /* Scope 2 attributes: used between end-to-end nodes. */ /* These must be last */ PACKETBUF_ADDR_SENDER, @@ -277,6 +283,8 @@ void packetbuf_attr_copyfrom(struct packetbuf_attr *attrs, #define PACKETBUF_ATTR_BYTE 8 #define PACKETBUF_ADDRSIZE (LINKADDR_SIZE * PACKETBUF_ATTR_BYTE) +#define PACKETBUF_ATTR_SECURITY_LEVEL_DEFAULT 0xffff + struct packetbuf_attrlist { uint8_t type; uint8_t len; diff --git a/os/services/rpl-border-router/native/border-router-mac.c b/os/services/rpl-border-router/native/border-router-mac.c index fbf8b6496..7fe4fc6ed 100644 --- a/os/services/rpl-border-router/native/border-router-mac.c +++ b/os/services/rpl-border-router/native/border-router-mac.c @@ -64,6 +64,20 @@ struct tx_callback { /*---------------------------------------------------------------------------*/ static struct tx_callback callbacks[MAX_CALLBACKS]; /*---------------------------------------------------------------------------*/ +void +init_sec(void) +{ + /* use the CSMA LLSEC config parameter */ +#if LLSEC802154_USES_AUX_HEADER + if(packetbuf_attr(PACKETBUF_ATTR_SECURITY_LEVEL) == + PACKETBUF_ATTR_SECURITY_LEVEL_DEFAULT) { + packetbuf_set_attr(PACKETBUF_ATTR_SECURITY_LEVEL, + CSMA_LLSEC_SECURITY_LEVEL); + } +#endif +} +/*---------------------------------------------------------------------------*/ + void packet_sent(uint8_t sessionid, uint8_t status, uint8_t tx) { @@ -164,6 +178,13 @@ off() return 1; } /*---------------------------------------------------------------------------*/ +static int +max_payload() +{ + init_sec(); + return 127 - NETSTACK_FRAMER.length(); +} +/*---------------------------------------------------------------------------*/ static void init(void) { @@ -176,6 +197,7 @@ const struct mac_driver border_router_mac_driver = { send_packet, packet_input, on, - off + off, + max_payload, }; /*---------------------------------------------------------------------------*/ diff --git a/os/services/rpl-border-router/native/slip-dev.c b/os/services/rpl-border-router/native/slip-dev.c index 7ea764836..3ccd1db4b 100644 --- a/os/services/rpl-border-router/native/slip-dev.c +++ b/os/services/rpl-border-router/native/slip-dev.c @@ -562,7 +562,7 @@ slip_init(void) slip_send(slipfd, SLIP_END); inslip = fdopen(slipfd, "r"); if(inslip == NULL) { - err(1, "main: fdopen"); + err(1, "slip_init: fdopen"); } } /*---------------------------------------------------------------------------*/ diff --git a/os/services/rpl-border-router/native/tun-bridge.c b/os/services/rpl-border-router/native/tun-bridge.c index b358bf2f9..26bc80bd7 100644 --- a/os/services/rpl-border-router/native/tun-bridge.c +++ b/os/services/rpl-border-router/native/tun-bridge.c @@ -210,7 +210,7 @@ tun_init() tunfd = tun_alloc(slip_config_tundev); if(tunfd == -1) { - err(1, "main: open"); + err(1, "tun_init: open"); } select_set_callback(tunfd, &tun_select_callback); diff --git a/os/services/shell/shell-commands.c b/os/services/shell/shell-commands.c index e8bb4b6b2..c8b7d862e 100644 --- a/os/services/shell/shell-commands.c +++ b/os/services/shell/shell-commands.c @@ -55,6 +55,9 @@ #if MAC_CONF_WITH_TSCH #include "net/mac/tsch/tsch.h" #endif /* MAC_CONF_WITH_TSCH */ +#if MAC_CONF_WITH_CSMA +#include "net/mac/csma/csma.h" +#endif #include "net/routing/routing.h" #include "net/mac/llsec802154.h" @@ -424,7 +427,7 @@ PT_THREAD(cmd_rpl_global_repair(struct pt *pt, shell_output_func output, char *a { PT_BEGIN(pt); - SHELL_OUTPUT(output, "Triggering routing global repair\n") + SHELL_OUTPUT(output, "Triggering routing global repair\n"); NETSTACK_ROUTING.global_repair("Shell"); PT_END(pt); @@ -447,7 +450,7 @@ PT_THREAD(cmd_rpl_refresh_routes(struct pt *pt, shell_output_func output, char * { PT_BEGIN(pt); - SHELL_OUTPUT(output, "Triggering routes refresh\n") + SHELL_OUTPUT(output, "Triggering routes refresh\n"); rpl_refresh_routes("Shell"); PT_END(pt); @@ -729,6 +732,73 @@ PT_THREAD(cmd_6top(struct pt *pt, shell_output_func output, char *args)) } #endif /* TSCH_WITH_SIXTOP */ /*---------------------------------------------------------------------------*/ +#if LLSEC802154_ENABLED +static +PT_THREAD(cmd_llsec_setlv(struct pt *pt, shell_output_func output, char *args)) +{ + + PT_BEGIN(pt); + + if(args == NULL) { + SHELL_OUTPUT(output, "Default LLSEC level is %d\n", + uipbuf_get_attr(UIPBUF_ATTR_LLSEC_LEVEL)); + PT_EXIT(pt); + } else { + int lv = atoi(args); + if(lv < 0 || lv > 7) { + SHELL_OUTPUT(output, "Illegal LLSEC Level %d\n", lv); + PT_EXIT(pt); + } else { + uipbuf_set_default_attr(UIPBUF_ATTR_LLSEC_LEVEL, lv); + uipbuf_clear_attr(); + SHELL_OUTPUT(output, "LLSEC default level set %d\n", lv); + } + } + + PT_END(pt); +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(cmd_llsec_setkey(struct pt *pt, shell_output_func output, char *args)) +{ + char *next_args; + + PT_BEGIN(pt); + + SHELL_ARGS_INIT(args, next_args); + + if(args == NULL) { + SHELL_OUTPUT(output, "Provide an index and a 16-char string for the key\n"); + PT_EXIT(pt); + } else { + int key; + SHELL_ARGS_NEXT(args, next_args); + key = atoi(args); + if(key < 0) { + SHELL_OUTPUT(output, "Illegal LLSEC Key index %d\n", key); + PT_EXIT(pt); + } else { +#if MAC_CONF_WITH_CSMA + /* Get next arg (key-string) */ + SHELL_ARGS_NEXT(args, next_args); + if(args == NULL) { + SHELL_OUTPUT(output, "Provide both an index and a key\n"); + } else if(strlen(args) == 16) { + csma_security_set_key(key, (const uint8_t *) args); + SHELL_OUTPUT(output, "Set key for index %d\n", key); + } else { + SHELL_OUTPUT(output, "Wrong length of key: '%s' (%d)\n", args, strlen(args)); + } +#else + SHELL_OUTPUT(output, "Set key not supported.\n"); + PT_EXIT(pt); +#endif + } + } + PT_END(pt); +} +#endif /* LLSEC802154_ENABLED */ +/*---------------------------------------------------------------------------*/ void shell_commands_init(void) { @@ -801,6 +871,10 @@ const struct shell_command_t builtin_shell_commands[] = { #if TSCH_WITH_SIXTOP { "6top", cmd_6top, "'> 6top help': Shows 6top command usage" }, #endif /* TSCH_WITH_SIXTOP */ +#if LLSEC802154_ENABLED + { "llsec-set-level", cmd_llsec_setlv, "'> llsec-set-level ': Set the level of link layer security (show if no lv argument)"}, + { "llsec-set-key", cmd_llsec_setkey, "'> llsec-set-key ': Set the key of link layer security"}, +#endif /* LLSEC802154_ENABLED */ { NULL, NULL, NULL }, }; diff --git a/os/services/shell/shell.c b/os/services/shell/shell.c index c219b1903..5347080a8 100644 --- a/os/services/shell/shell.c +++ b/os/services/shell/shell.c @@ -98,19 +98,22 @@ PT_THREAD(shell_input(struct pt *pt, shell_output_func output, const char *cmd)) cmd++; } - /* Look for arguments */ - args = strchr(cmd, ' '); - if(args != NULL) { - *args = '\0'; - args++; - } + /* Skip empty lines */ + if(*cmd != '\0') { + /* Look for arguments */ + args = strchr(cmd, ' '); + if(args != NULL) { + *args = '\0'; + args++; + } - cmd_descr = shell_command_lookup(cmd); - if(cmd_descr != NULL) { - static struct pt cmd_pt; - PT_SPAWN(pt, &cmd_pt, cmd_descr->func(&cmd_pt, output, args)); - } else { - SHELL_OUTPUT(output, "Command not found. Type 'help' for a list of commands\n"); + cmd_descr = shell_command_lookup(cmd); + if(cmd_descr != NULL) { + static struct pt cmd_pt; + PT_SPAWN(pt, &cmd_pt, cmd_descr->func(&cmd_pt, output, args)); + } else { + SHELL_OUTPUT(output, "Command not found. Type 'help' for a list of commands\n"); + } } output_prompt(output); diff --git a/tests/19-out-of-tree-build/Makefile b/tests/19-out-of-tree-build/Makefile new file mode 100644 index 000000000..30d7e2302 --- /dev/null +++ b/tests/19-out-of-tree-build/Makefile @@ -0,0 +1,20 @@ +EXAMPLESDIR=$(HOME)/out-of-tree-tests +TOOLSDIR=$(HOME)/contiki-ng/tools + +EXAMPLES = \ +hello-world/native \ +hello-world/native:MAKE_NET=MAKE_NET_NULLNET \ +hello-world/native:MAKE_ROUTING=MAKE_ROUTING_RPL_CLASSIC \ +hello-world/sky \ +hello-world/nrf52dk \ +hello-world/cc2538dk \ +hello-world/zoul \ +hello-world/openmote-cc2538 \ +hello-world/cc26x0-cc13x0 \ +hello-world/jn516x \ +hello-world/simplelink:BOARD=launchpad/cc26x2r1 \ +hello-world/simplelink:BOARD=sensortag/cc2650 \ + +TOOLS= + +include ../Makefile.compile-test diff --git a/tools/cooja b/tools/cooja index a5904b983..63538bbb8 160000 --- a/tools/cooja +++ b/tools/cooja @@ -1 +1 @@ -Subproject commit a5904b98366478bb9e7f7fe9f0bb78fc064914c5 +Subproject commit 63538bbb882ba06a7b8cf97c11ce2fe4d22e4f88 diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 9d15704ac..6eb9dbb17 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -1,29 +1,58 @@ FROM 32bit/ubuntu:16.04 +ENV DEBIAN_FRONTEND noninteractive + # Tools -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - build-essential doxygen git wget unzip python-serial python-pip \ - default-jdk ant srecord iputils-tracepath rlwrap \ - mosquitto mosquitto-clients gdb \ - && apt-get clean +RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF && \ + echo "deb http://download.mono-project.com/repo/ubuntu xenial main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list && \ + apt-get -qq update && \ + apt-get -qq -y --no-install-recommends install \ + ant \ + build-essential \ + default-jdk \ + doxygen \ + gdb \ + git \ + gksu \ + gtk-sharp2 \ + iputils-tracepath \ + libcanberra-gtk-module:i386 \ + libgtk2.0-0 \ + mono-complete \ + mosquitto \ + mosquitto-clients \ + npm \ + python-pip \ + python-serial \ + rlwrap \ + screen \ + srecord \ + uml-utilities \ + unzip \ + wget \ + > /dev/null \ + && apt-get -qq clean + +# Install coap-cli +RUN npm -q install coap-cli -g \ + && sudo ln -s /usr/bin/nodejs /usr/bin/node # Install ARM toolchain -RUN wget https://launchpad.net/gcc-arm-embedded/5.0/5-2015-q4-major/+download/gcc-arm-none-eabi-5_2-2015q4-20151219-linux.tar.bz2 && \ +RUN wget -nv https://launchpad.net/gcc-arm-embedded/5.0/5-2015-q4-major/+download/gcc-arm-none-eabi-5_2-2015q4-20151219-linux.tar.bz2 && \ tar xjf gcc-arm-none-eabi-5_2-2015q4-20151219-linux.tar.bz2 -C /tmp/ && \ cp -f -r /tmp/gcc-arm-none-eabi-5_2-2015q4/* /usr/local/ && \ rm -rf /tmp/gcc-arm-none-eabi-* gcc-arm-none-eabi-*-linux.tar.bz2 # Install msp430 toolchain -RUN wget http://simonduq.github.io/resources/mspgcc-4.7.2-compiled.tar.bz2 && \ +RUN wget -nv http://simonduq.github.io/resources/mspgcc-4.7.2-compiled.tar.bz2 && \ tar xjf mspgcc*.tar.bz2 -C /tmp/ && \ cp -f -r /tmp/msp430/* /usr/local/ && \ rm -rf /tmp/msp430 mspgcc*.tar.bz2 # Install NXP toolchain (partial, with binaries excluded. Download from nxp.com) -RUN wget http://simonduq.github.io/resources/ba-elf-gcc-4.7.4-part1.tar.bz2 && \ - wget http://simonduq.github.io/resources/ba-elf-gcc-4.7.4-part2.tar.bz2 && \ - wget http://simonduq.github.io/resources/jn516x-sdk-4163-1416.tar.bz2 && \ +RUN wget -nv http://simonduq.github.io/resources/ba-elf-gcc-4.7.4-part1.tar.bz2 && \ + wget -nv http://simonduq.github.io/resources/ba-elf-gcc-4.7.4-part2.tar.bz2 && \ + wget -nv http://simonduq.github.io/resources/jn516x-sdk-4163-1416.tar.bz2 && \ mkdir /tmp/jn516x-sdk /tmp/ba-elf-gcc && \ tar xjf jn516x-sdk-*.tar.bz2 -C /tmp/jn516x-sdk && \ tar xjf ba-elf-gcc-*part1.tar.bz2 -C /tmp/ba-elf-gcc && \ @@ -35,18 +64,17 @@ RUN wget http://simonduq.github.io/resources/ba-elf-gcc-4.7.4-part1.tar.bz2 && \ ENV PATH="/usr/ba-elf-gcc/bin:${PATH}" ## Install nRF52 SDK -RUN wget https://developer.nordicsemi.com/nRF5_IoT_SDK/nRF5_IoT_SDK_v0.9.x/nrf5_iot_sdk_3288530.zip && \ +RUN wget -nv https://developer.nordicsemi.com/nRF5_IoT_SDK/nRF5_IoT_SDK_v0.9.x/nrf5_iot_sdk_3288530.zip && \ mkdir /usr/nrf52-sdk && \ - unzip nrf5_iot_sdk_3288530.zip -d /usr/nrf52-sdk && \ + unzip -q nrf5_iot_sdk_3288530.zip -d /usr/nrf52-sdk && \ rm nrf5_iot_sdk_3288530.zip ENV NRF52_SDK_ROOT /usr/nrf52-sdk # Install sphinx and sphinx_rtd_theme, required for building and testing the # readthedocs API documentation -RUN pip install --upgrade pip -RUN pip install setuptools -RUN pip install sphinx_rtd_theme sphinx +RUN pip -q install --upgrade pip +RUN pip -q install setuptools && pip -q install sphinx_rtd_theme sphinx # Create user, enable X forwarding, add to group dialout # -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix @@ -74,21 +102,8 @@ WORKDIR ${HOME} RUN echo "#!/bin/bash\nant -Dbasedir=${COOJA} -f ${COOJA}/build.xml run" > ${HOME}/cooja && \ chmod +x ${HOME}/cooja -# Install coap-cli -RUN sudo apt-get install -y npm \ - && sudo apt-get clean \ - && sudo npm install coap-cli -g \ - && sudo ln -s /usr/bin/nodejs /usr/bin/node - -# Install Mono and libcanberra-gtk:i386 (for Renode) -RUN sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF \ - && echo "deb http://download.mono-project.com/repo/ubuntu xenial main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list \ - && sudo apt-get update \ - && sudo apt-get install -y mono-complete gksu libgtk2.0-0 screen uml-utilities gtk-sharp2 libcanberra-gtk-module:i386 \ - && sudo apt-get clean - # Download, build and install Renode -RUN git clone https://github.com/renode/renode.git \ +RUN git clone --quiet https://github.com/renode/renode.git \ && cd ${HOME}/renode \ && git checkout v1.3 \ && ./build.sh