diff --git a/README.md b/README.md
index 843da31..6f35202 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,113 @@
-# ZodiacFX
-Firmware for the Northbound Networks Zodiac FX OpenFlow Switch
+# Zodiac FX Firmware
+
+This is the firmware for the [Northbound Networks](https://northboundnetworks.com/) Zodiac FX OpenFlow Switch.
+
+## Background
+
+The Zodiac FX began as a [Kickstarter campaign](https://www.kickstarter.com/projects/northboundnetworks/zodiac-fx-the-worlds-smallest-openflow-sdn-switch) in 2015, with the goal of providing an affordable Software Defined Networking (SDN) platform for developers, researchers, and networking hobbyists. To learn more about SDN, visit the [Northbound Networks Blog](https://northboundnetworks.com/blogs/sdn).
+
+The Zodiac FX SDN switch uses the [OpenFlow protocol](https://www.opennetworking.org/sdn-resources/openflow), an open standard for communication in an SDN architecture. OpenFlow allows communication between the SDN controller (where applications can be run) and OpenFlow switches in the network. These switches use application-generated "Flows" to determine how network data is processed.
+
+This repository contains the entire open-source firmware for the Zodiac FX including OpenFlow libraries. The firmware is constantly being updated with support for features of the OpenFlow specification, and to improve compatability with the various SDN controllers. OpenFlow version 1.0 and version 1.3 are currently supported.
+
+## Flashing/Updating the Firmware
+
+The latest firmware is available in the [Northbound Networks Forums](http://forums.northboundnetworks.com/index.php?topic=52.0).
+
+Starting from version 0.80, Zodiac FX supports firmware updates via the CLI and web interface. In order to make this possible, major changes were made to the firmware flashing process. Follow the update process below, based on your current firmware version.
+
+#### For firmware versions BEFORE version 0.80
+
+To update to version 0.80 or later, a **full upgrade firmware** needs to be flashed.
+
+Download the latest **full upgrade firmware** from the [Northbound Networks Forums](http://forums.northboundnetworks.com/index.php?topic=52.0) - 'Full Upgrade Firmware (v0.XX) - ZodiacFX_vXX_full_install.bin'
+
+Follow the firmware update process detailed in **Section 2. Updating Firmware** in the [Zodiac FX User Guide](http://forums.northboundnetworks.com/downloads/zodiac_fx/guides/ZodiacFX_UserGuide_0317.pdf).
+
+#### For firmware versions AFTER version 0.80
+
+The update process has been simplified for the newer releases.
+
+Download the latest **update firmware** from the [Northbound Networks Forums](http://forums.northboundnetworks.com/index.php?topic=52.0) - 'Update Firmware (v0.XX) - ZodiacFX_vXX_update.bin'
+
+* **To update via the CLI**:
+ * In the root context, type the 'update' command
+ * When prompted, begin the firmware update via the XMODEM protocol
+ * Note: not all serial terminal applications support XMODEM
+ * If the firmware update is successful, Zodiac FX will automatically restart to complete the update
+
+* **To update via the web interface**:
+ * Go to the 'Update f/w' page in the Zodiac FX web interface
+ * Note: the web interface is available by going to the Zodiac FX IP address in a web browser on the controller
+ * This feature is currently fully supported in Google Chrome
+ * Browse and select the downloaded firmware
+ * Click 'Upload File' and wait for a confirmation page to appear
+ * Click 'Restart' in the web interface header to complete the update
+
+* **[Advanced] To update via cURL**:
+ * Run the following command: **curl --verbose -0 --form "file=@ZodiacFX_vXX_update.bin"**
+ * If the firmware upload fails, you may need to use the multipart/related content type like so: **curl -H "Content-Type: multipart/related" --verbose -0 --form "file=@ZodiacFX_vXX_update.bin"**
+ * Note: a restart is required after the update to load the new firmware.
+
+## Building the Project
+
+If you want to modify the firmware for your own project, either download this project or fork this repository.
+
+[Atmel Studio 7](https://www.atmel.com/Microsite/atmel-studio/) is required to build the project.
+
+#### Debugging the project
+
+For full source-level debugging, a [Zodiac FX Hardware Debugger](https://northboundnetworks.com/products/zodiac-fx-hardware-debugger) is required.
+
+* Ensure that the hardware debugger appears in Project -> ZodiacFX Properties -> Tool -> Selected debugger/programmer
+ * Zodiac FX uses the JTAG interface
+* Select the 'Debug' Solution Configuration in the Atmel Studio Standard toolbar
+ * The 'Release' configuration has been modified to build firmware updates, and will not run directly in Atmel Studio
+* Select the 'Start Debugging and Break' option in the Debug menu to begin stepping through the source
+
+The firmware will continue to run by cycling power to the Zodiac FX (after removing the hardware debugger). However, firmware updating will not function until a **full upgrade firmware** is flashed. The modified firmware can be written to the Zodiac FX by following the steps outlined below: **running the code without a hardware debugger**.
+
+#### Running the code without a hardware debugger
+
+Modified firmware can be tested without the Zodiac FX Hardware Debugger, however source-level debugging is not possible.
+
+* Build the 'Release' configuration of the ZodiacFX solution
+* Navigate to the compiled binary
+ * \ZodiacFX\Release\ZodiacFX.bin
+* Follow the steps in Signing Binaries to allow the Zodiac FX to update to the modified firmware
+
+## Signing Binaries
+
+The Zodiac FX uses a simple additive checksum to verify the integrity of the uploaded firmware.
+
+To sign your own modified firmware, follow the steps below:
+* Build a 'Release' binary of the modified firmware
+* Update the Zodiac FX with the modified firmware
+ * Follow the instructions outlined in Flashing/Updating the Firmware - For firmware versions AFTER version 0.80
+* The firmware will fail the verification check, but will still be stored inside the Zodiac FX flash memory
+* In the root context of the CLI, type in the hidden command 'get crc'
+* Open the ZodiacFX.bin file in a hex editor, and append the 8 bytes to the end of the firmware file
+ * For example, if 'get crc' provides [A05A1201 00000000], append 'A0 5A 12 01 00 00 00 00' to the end of the firmware file
+* Update the Zodiac FX again with the (now signed) modified firmware
+* The firmware update should be successful, and the Zodiac FX will run the new firmware after restarting
+
+## Reporting Bugs and Issues
+
+Any bugs and issues can be brought up in the [Northbound Networks Forums](http://forums.northboundnetworks.com/index.php?board=3.0).
+
+Issues can also be [raised](https://github.com/NorthboundNetworks/ZodiacFX/issues) in this repository.
+
+## Release Notes
+
+**Version 0.80**
+* Firmware upload via CLI and web interface added
+* Metering added to OpenFlow 1.3
+
+## Authors
+
+* **Paul Zanna** - Creator
+* **Kristopher Chen** - Firmware Developer
+
+## License
+
+[GPL 3.0](LICENSE)
diff --git a/ZodiacFX/ZodiacFX.cproj b/ZodiacFX/ZodiacFX.cproj
index 7af9923..e3e4036 100644
--- a/ZodiacFX/ZodiacFX.cproj
+++ b/ZodiacFX/ZodiacFX.cproj
@@ -274,11 +274,11 @@
JTAG
com.atmel.avrdbg.tool.atmelice
- J41800009874
+ J41800058832
Atmel-ICE
JTAG
- J41800009874
+ J41800058832
0xA3CC0CE0
7500000
@@ -368,7 +368,7 @@
True
- -Wl,--defsym,__stack_size__=0x1400 -Wl,--entry=Reset_Handler -Wl,--cref -mthumb -T../src/ASF/sam/utils/linker_scripts/sam4e/sam4e8/gcc/flash.ld
+ -Wl,--defsym,__stack_size__=0x1400 -Wl,--entry=Reset_Handler -Wl,-section-start=.text=0x00420000 -Wl,--cref -mthumb -T../src/ASF/sam/utils/linker_scripts/sam4e/sam4e8/gcc/flash.ld
../src/ASF/sam/drivers/efc
diff --git a/ZodiacFX/src/command.c b/ZodiacFX/src/command.c
index 38c4065..864f33d 100644
--- a/ZodiacFX/src/command.c
+++ b/ZodiacFX/src/command.c
@@ -48,6 +48,7 @@
// Global variables
extern struct zodiac_config Zodiac_Config;
+extern struct verification_data verify;
extern bool debug_output;
extern int charcount, charcount_last;
@@ -62,6 +63,8 @@ extern int iLastFlow;
extern struct ofp10_port_stats phys10_port_stats[4];
extern struct ofp13_port_stats phys13_port_stats[4];
extern struct table_counter table_counters[MAX_TABLES];
+extern struct meter_entry13 *meter_entry[MAX_METER_13];
+extern struct meter_band_stats_array band_stats_array[MAX_METER_13];
extern bool masterselect;
extern bool stackenabled = false;
extern bool trace = false;
@@ -71,6 +74,7 @@ extern int totaltime;
extern int32_t ul_temp;
extern int OF_Version;
extern uint32_t uid_buf[4];
+extern bool restart_required_outer;
// Local Variables
bool showintro = true;
@@ -135,6 +139,15 @@ void task_command(char *str, char *str_last)
char *param3;
char *pch;
+ if(restart_required_outer == true)
+ {
+ printf("Restarting the Zodiac FX, please reopen your terminal application.\r\n");
+ for(int x = 0;x<100000;x++); // Let the above message get sent to the terminal before detaching
+ udc_detach(); // Detach the USB device before restart
+ rstc_start_software_reset(RSTC); // Software reset
+ while (1);
+ }
+
while(udi_cdc_is_rx_ready()){
ch = udi_cdc_getc();
@@ -440,6 +453,15 @@ void command_root(char *command, char *param1, char *param2, char *param3)
while (1);
}
+ // Get CRC
+ if (strcmp(command, "get")==0 && strcmp(param1, "crc")==0)
+ {
+ verification_check();
+ printf("Calculated verification: %08x\r\n", verify.calculated);
+ printf("Append [%08x 00000000] to the binary\r\n", ntohl(verify.calculated));
+ return;
+ }
+
// Unknown Command
printf("Unknown command\r\n");
return;
@@ -1021,7 +1043,6 @@ void command_openflow(char *command, char *param1, char *param2, char *param3)
int match_size;
int inst_size;
int act_size;
- struct ofp13_instruction *inst_ptr;
struct ofp13_instruction_actions *inst_actions;
struct oxm_header13 oxm_header;
uint8_t oxm_value8;
@@ -1146,22 +1167,38 @@ void command_openflow(char *command, char *param1, char *param2, char *param3)
int min = t/60;
int sec = t%60;
printf(" Last Match: %02d:%02d:%02d\r\n", hr, min, sec);
+
// Print instruction list
if (ofp13_oxm_inst[i] != NULL)
{
+ // Get a list of all instructions for this flow
+ void *insts[8] = {0};
+ inst_size = 0;
+ while(inst_size < ofp13_oxm_inst_size[i]){
+ struct ofp13_instruction *inst_ptr = (struct ofp13_instruction *)(ofp13_oxm_inst[i] + inst_size);
+ insts[ntohs(inst_ptr->type)] = inst_ptr;
+ inst_size += ntohs(inst_ptr->len);
+ }
+
printf("\r Instructions:\r\n");
- inst_ptr = (struct ofp13_instruction *) ofp13_oxm_inst[i];
- inst_size = ntohs(inst_ptr->len);
- if(ntohs(inst_ptr->type) == OFPIT13_APPLY_ACTIONS)
+
+ // Check for optional metering instruction
+ if(insts[OFPIT13_METER] != NULL)
+ {
+ struct ofp13_instruction_meter *inst_meter = insts[OFPIT13_METER];
+ printf(" Meter: %d\r\n", ntohl(inst_meter->meter_id));
+ }
+
+ if(insts[OFPIT13_APPLY_ACTIONS] != NULL)
{
printf(" Apply Actions:\r\n");
struct ofp13_action_header *act_hdr;
act_size = 0;
- if (inst_size == sizeof(struct ofp13_instruction_actions)) printf(" DROP \r\n"); // No actions
- while (act_size < (inst_size - sizeof(struct ofp13_instruction_actions)))
+ inst_actions = insts[OFPIT13_APPLY_ACTIONS];
+ if (ntohs(inst_actions->len) == sizeof(struct ofp13_instruction_actions)) printf(" DROP \r\n"); // No actions
+ while (act_size < (ntohs(inst_actions->len) - sizeof(struct ofp13_instruction_actions)))
{
- inst_actions = ofp13_oxm_inst[i] + act_size;
- act_hdr = &inst_actions->actions;
+ act_hdr = (struct ofp13_action_header*)((uintptr_t)inst_actions->actions + act_size);
if (htons(act_hdr->type) == OFPAT13_OUTPUT)
{
struct ofp13_action_output *act_output = act_hdr;
@@ -1304,26 +1341,11 @@ void command_openflow(char *command, char *param1, char *param2, char *param3)
}
}
// Print goto table instruction
- if(ntohs(inst_ptr->type) == OFPIT13_GOTO_TABLE)
+ if(insts[OFPIT13_GOTO_TABLE] != NULL)
{
struct ofp13_instruction_goto_table *inst_goto_ptr;
- inst_goto_ptr = (struct ofp13_instruction_goto_table *) inst_ptr;
+ inst_goto_ptr = (struct ofp13_instruction_goto_table *) insts[OFPIT13_GOTO_TABLE];
printf(" Goto Table: %d\r\n", inst_goto_ptr->table_id);
- continue;
- }
- // Is there more then one instruction?
- if (ofp13_oxm_inst_size[i] > inst_size)
- {
- uint8_t *nxt_inst;
- nxt_inst = ofp13_oxm_inst[i] + inst_size;
- inst_ptr = (struct ofp13_instruction *) nxt_inst;
- inst_size = ntohs(inst_ptr->len);
- if(ntohs(inst_ptr->type) == OFPIT13_GOTO_TABLE)
- {
- struct ofp13_instruction_goto_table *inst_goto_ptr;
- inst_goto_ptr = (struct ofp13_instruction_goto_table *) inst_ptr;
- printf(" Goto Table: %d\r\n", inst_goto_ptr->table_id);
- }
}
} else {
// No instructions
@@ -1463,6 +1485,90 @@ void command_openflow(char *command, char *param1, char *param2, char *param3)
return;
}
+ // Show meter table entries
+ if (strcmp(command, "show") == 0 && strcmp(param1, "meters") == 0)
+ {
+ int meter_out_counter = 1;
+
+ // Check that table is populated
+ if(meter_entry[0] != NULL)
+ {
+ int meter_index = 0;
+ while(meter_entry[meter_index] != NULL && meter_index < MAX_METER_13)
+ {
+ printf("\r\n-------------------------------------------------------------------------\r\n");
+ printf("\r\nMeter %d\r\n", meter_out_counter);
+ meter_out_counter++;
+ printf(" Meter ID: %d\r\n", meter_entry[meter_index]->meter_id);
+ printf(" Counters:\r\n");
+ meter_entry[meter_index]->flow_count = get_bound_flows(meter_entry[meter_index]->meter_id);
+ printf("\tBound Flows:\t%d\tDuration:\t%d sec\r\n", meter_entry[meter_index]->flow_count, (sys_get_ms()-meter_entry[meter_index]->time_added)/1000);
+ printf("\tByte Count:\t%"PRIu64"\tPacket Count:\t%"PRIu64"\r\n", meter_entry[meter_index]->byte_in_count, meter_entry[meter_index]->packet_in_count);
+ printf("\tConfiguration:\t");
+ if(((meter_entry[meter_index]->flags) & OFPMF13_KBPS) == OFPMF13_KBPS)
+ {
+ printf("KBPS; ");
+ }
+ if(((meter_entry[meter_index]->flags) & OFPMF13_PKTPS) == OFPMF13_PKTPS)
+ {
+ printf("PKTPS; ");
+ }
+ if(((meter_entry[meter_index]->flags) & OFPMF13_BURST) == OFPMF13_BURST)
+ {
+ printf("BURST; ");
+ }
+ if(((meter_entry[meter_index]->flags) & OFPMF13_STATS) == OFPMF13_STATS)
+ {
+ printf("STATS; ");
+ }
+ if(meter_entry[meter_index]->flags == 0)
+ {
+ printf(" NONE;");
+ }
+
+ printf("\r\n\tNumber of bands:\t%d\r\n", meter_entry[meter_index]->band_count);
+ int bands_processed = 0;
+ struct ofp13_meter_band_drop * ptr_band;
+ ptr_band = &(meter_entry[meter_index]->bands);
+ while(bands_processed < meter_entry[meter_index]->band_count)
+ {
+ printf("\t\tBand %d:\r\n", bands_processed+1);
+ printf("\t\t Type:\t\t");
+ if(ptr_band->type == OFPMBT13_DROP)
+ {
+ printf("DROP\r\n");
+ }
+ else if(ptr_band->type == OFPMBT13_DSCP_REMARK)
+ {
+ printf("DSCP REMARK (unsupported)\r\n");
+ }
+ else
+ {
+ printf("unsupported type\r\n");
+ }
+ printf("\t\t Rate:\t\t%d\t\r\n", ptr_band->rate);
+ printf("\t\t Burst Size:\t%d\t\r\n", ptr_band->burst_size);
+
+ // Find band index
+ int band_index = ((uint8_t*)ptr_band - (uint8_t*)&(meter_entry[meter_index]->bands)) / sizeof(struct ofp13_meter_band_drop);
+
+ // Display counters
+ printf("\t\t Byte count:\t%"PRIu64"\t\r\n", band_stats_array[meter_index].band_stats[band_index].byte_band_count);
+ printf("\t\t Packet count:\t%"PRIu64"\t\r\n", band_stats_array[meter_index].band_stats[band_index].packet_band_count);
+
+ ptr_band++; // Move to next band
+ bands_processed++;
+ }
+ meter_index++;
+ }
+ printf("\r\n-------------------------------------------------------------------------\r\n\r\n");
+ }
+ else
+ {
+ printf("No meters configured.\r\n");
+ }
+ return;
+ }
// Unknown Command
printf("Unknown command\r\n");
return;
@@ -1525,36 +1631,7 @@ void command_debug(char *command, char *param1, char *param2, char *param3)
trace = true;
printf("Starting trace...\r\n");
return;
- }
-
- if (strcmp(command, "check_flash")==0)
- {
- // Display contents of firmware update region (ending @ first 0xFFFFFFFF)
- unsigned long* pmem = (unsigned long*)0x00450000;
- while(pmem <= 0x00480000)
- {
- if(*pmem == 0xFFFFFFFF)
- {
- return;
- }
- printf("Addr: %p Val: 0x%l08x\n\r", (void *)pmem, *pmem);
- pmem++;
- }
- return;
- }
-
- if (strcmp(command, "check_flash_all")==0)
- {
- // Display contents of firmware update region
- unsigned long* pmem = (unsigned long*)0x00450000;
- while(pmem <= 0x00480000)
- {
- printf("Addr: %p Val: 0x%l08x\n\r", (void *)pmem, *pmem);
- pmem++;
- }
- return;
- }
-
+ }
// Unknown Command response
printf("Unknown command\r\n");
@@ -1624,6 +1701,7 @@ void printhelp(void)
printf("OpenFlow:\r\n");
printf(" show status\r\n");
printf(" show flows\r\n");
+ printf(" show meters\r\n");
printf(" enable\r\n");
printf(" disable\r\n");
printf(" clear flows\r\n");
diff --git a/ZodiacFX/src/config/conf_membag.h b/ZodiacFX/src/config/conf_membag.h
index e0344d5..a3dcf40 100644
--- a/ZodiacFX/src/config/conf_membag.h
+++ b/ZodiacFX/src/config/conf_membag.h
@@ -57,7 +57,7 @@
MEMBAG(56, 32), MEMBAG(56, 32), MEMBAG(56, 32), MEMBAG(56, 32),\
MEMBAG(72, 32), MEMBAG(72, 32), MEMBAG(72, 32), MEMBAG(72, 32),\
MEMBAG(72, 32), MEMBAG(72, 32), MEMBAG(72, 32), MEMBAG(72, 32),\
- MEMBAG(96, 32), MEMBAG(96, 32), MEMBAG(96, 32), MEMBAG(96, 32),
+ MEMBAG(96, 32), MEMBAG(96, 32), MEMBAG(96, 32), MEMBAG(96, 32)
#define CONF_MEMBAG_POOL_SIZE\
MEMBAG_SIZE(16, 32) + MEMBAG_SIZE(16, 32) + MEMBAG_SIZE(16, 32) + MEMBAG_SIZE(16, 32) +\
@@ -67,6 +67,6 @@
MEMBAG_SIZE(56, 32) + MEMBAG_SIZE(56, 32) + MEMBAG_SIZE(56, 32) + MEMBAG_SIZE(56, 32) +\
MEMBAG_SIZE(72, 32) + MEMBAG_SIZE(72, 32) + MEMBAG_SIZE(72, 32) + MEMBAG_SIZE(72, 32) +\
MEMBAG_SIZE(72, 32) + MEMBAG_SIZE(72, 32) + MEMBAG_SIZE(72, 32) + MEMBAG_SIZE(72, 32) +\
- MEMBAG_SIZE(96, 32) + MEMBAG_SIZE(96, 32) + MEMBAG_SIZE(96, 32) + MEMBAG_SIZE(96, 32)
+ MEMBAG_SIZE(96, 32) + MEMBAG_SIZE(96, 32) + MEMBAG_SIZE(96, 32) + MEMBAG_SIZE(96, 32)
#endif /* CONF_MEMBAG_H */
diff --git a/ZodiacFX/src/config/config_zodiac.h b/ZodiacFX/src/config/config_zodiac.h
index 98ee342..6698768 100644
--- a/ZodiacFX/src/config/config_zodiac.h
+++ b/ZodiacFX/src/config/config_zodiac.h
@@ -31,7 +31,7 @@
#define CONFIG_ZODIAC_H_
-#define VERSION "0.72" // Firmware version number
+#define VERSION "0.80" // Firmware version number
#define MAX_OFP_VERSION 0x04
@@ -46,4 +46,9 @@
#define HB_TIMEOUT 6 // Number of seconds to wait when there is no response from the controller
+#define MAX_OF_STATS 15 // Maximum number of flows to send to controller
+
+#define MAX_METER_13 8 // Maximum number of meter entries in meter table
+#define MAX_METER_BANDS_13 3 // Maximum number of meter bands per meter
+
#endif /* CONFIG_ZODIAC_H_ */
diff --git a/ZodiacFX/src/config/lwipopts.h b/ZodiacFX/src/config/lwipopts.h
index b488894..8c7d60b 100644
--- a/ZodiacFX/src/config/lwipopts.h
+++ b/ZodiacFX/src/config/lwipopts.h
@@ -101,7 +101,7 @@
* MEM_SIZE: the size of the heap memory. If the application will send
* a lot of data that needs to be copied, this should be set high.
*/
-#define MEM_SIZE 4 * 1024
+#define MEM_SIZE 6 * 1024
/**
* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
@@ -126,7 +126,7 @@
* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments.
* (requires the LWIP_TCP option)
*/
-#define MEMP_NUM_TCP_SEG 16
+#define MEMP_NUM_TCP_SEG 25
/**
* MEMP_NUM_REASSDATA: the number of IP packets simultaneously queued for
@@ -223,7 +223,7 @@
* when opening a connection. For the transmit size, this MSS sets
* an upper limit on the MSS advertised by the remote host.
*/
-#define TCP_MSS 1460
+#define TCP_MSS 536
/**
* TCP_WND: The size of a TCP window. This must be at least
@@ -235,7 +235,7 @@
* TCP_SND_BUF: TCP sender buffer space (bytes).
* To achieve good performance, this should be at least 2 * TCP_MSS.
*/
-#define TCP_SND_BUF (2 * TCP_MSS)
+#define TCP_SND_BUF (6 * TCP_MSS)
/**
* TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least
diff --git a/ZodiacFX/src/flash.c b/ZodiacFX/src/flash.c
index 0e345c8..25ac197 100644
--- a/ZodiacFX/src/flash.c
+++ b/ZodiacFX/src/flash.c
@@ -34,9 +34,12 @@
#include "flash.h"
#include "config_zodiac.h"
#include "openflow/openflow.h"
+#include "trace.h"
+#include "command.h"
// Global variables
extern uint8_t shared_buffer[SHARED_BUFFER_LEN];
+struct verification_data verify;
// Static variables
static uint32_t page_addr;
@@ -113,6 +116,7 @@ int firmware_update_init(void)
*/
int flash_write_page(uint8_t *flash_page)
{
+ TRACE("flash.c: writing to 0x%08x", flash_page_addr);
if(flash_page_addr <= IFLASH_ADDR + IFLASH_SIZE - IFLASH_PAGE_SIZE)
{
ul_rc = flash_write(flash_page_addr, flash_page,
@@ -145,13 +149,97 @@ void cli_update(void)
{
printf("Error: failed to write firmware to memory\r\n");
}
- printf("Firmware upload complete - Restarting the Zodiac FX.\r\n");
- for(int x = 0;x<100000;x++); // Let the above message get send to the terminal before detaching
- udc_detach(); // Detach the USB device before restart
- rstc_start_software_reset(RSTC); // Software reset
+ if(verification_check() == SUCCESS)
+ {
+ printf("Firmware upload complete - Restarting the Zodiac FX.\r\n");
+ for(int x = 0;x<100000;x++); // Let the above message get send to the terminal before detaching
+ udc_detach(); // Detach the USB device before restart
+ rstc_start_software_reset(RSTC); // Software reset
+ }
+ else
+ {
+ printf("\r\n");
+ printf("Firmware verification check failed\r\n");
+ printf("\r\n");
+ }
+
return;
}
+/*
+* Verify firmware data
+*
+*/
+int verification_check(void)
+{
+ char* fw_end_pmem = (char*)FLASH_BUFFER_END; // Buffer pointer to store the last address
+ char* fw_step_pmem = (char*)FLASH_BUFFER; // Buffer pointer to the starting address
+ uint32_t crc_sum = 0; // Store CRC sum
+ uint8_t pad_error = 0; // Set when padding is not found
+
+ /* Add all bytes of the uploaded firmware */
+ // Decrement the pointer until the previous address has data in it (not 0xFF)
+ while(*(fw_end_pmem-1) == '\xFF' && fw_end_pmem > FLASH_BUFFER)
+ {
+ fw_end_pmem--;
+ }
+
+ for(int sig=1; sig<=4; sig++)
+ {
+ if(*(fw_end_pmem-sig) != NULL)
+ {
+ TRACE("signature padding %d not found - last address: %08x", sig, fw_end_pmem);
+ pad_error = 1;
+ }
+ else
+ {
+ TRACE("signature padding %d found", sig);
+ }
+ }
+
+ // Start summing all bytes
+ if(pad_error)
+ {
+ // Calculate CRC for debug
+ while(fw_step_pmem < fw_end_pmem)
+ {
+ crc_sum += *fw_step_pmem;
+ fw_step_pmem++;
+ }
+ }
+ else
+ {
+ // Exclude CRC & padding from calculation
+ while(fw_step_pmem < (fw_end_pmem-8))
+ {
+ crc_sum += *fw_step_pmem;
+ fw_step_pmem++;
+ }
+ }
+
+ TRACE("fw_step_pmem %08x; fw_end_pmem %08x;", fw_step_pmem, fw_end_pmem);
+
+ // Update structure entry
+ TRACE("CRC sum: %04x", crc_sum);
+ verify.calculated = crc_sum;
+
+ /* Compare with last 4 bytes of firmware */
+ // Get last 4 bytes of firmware (4-byte CRC, 4-byte padding)
+ verify.found = *(uint32_t*)(fw_end_pmem - 8);
+
+ TRACE("CRC found: %04x", verify.found);
+
+ // Compare calculated and found CRC
+ if(verify.found == verify.calculated)
+ {
+ return SUCCESS;
+ }
+ else
+ {
+ return FAILURE;
+ }
+}
+
/*
* XModem transfer
*
@@ -159,7 +247,8 @@ void cli_update(void)
int xmodem_xfer(void)
{
char ch;
- int timeout_clock = 0;
+ int timeout_clock = 0; // protocol (NAK) timeout counter
+ int timeout_upload = 0; // upload timeout counter
int buff_ctr = 1;
int byte_ctr = 1;
int block_ctr = 0;
@@ -237,10 +326,15 @@ int xmodem_xfer(void)
byte_ctr++;
}
timeout_clock++;
- if (timeout_clock > 1000000) // Timeout, send
+ if(timeout_upload > 6)
+ {
+ return;
+ }
+ else if (timeout_clock > 1000000) // Timeout, send
{
printf("%c", X_NAK);
timeout_clock = 0;
+ timeout_upload++;
}
}
}
diff --git a/ZodiacFX/src/flash.h b/ZodiacFX/src/flash.h
index 06f1fde..7c25a9e 100644
--- a/ZodiacFX/src/flash.h
+++ b/ZodiacFX/src/flash.h
@@ -40,6 +40,14 @@ __no_inline RAMFUNC void firmware_update(void);
int xmodem_xfer(void);
void xmodem_clear_padding(uint8_t *buff);
+int verification_check(void);
+
+struct verification_data
+{
+ uint32_t calculated; // Last 4 bytes from summed data
+ uint32_t found; // 4 bytes at the end of uploaded firmware
+};
+
#define X_EOT 0x04
#define X_ACK 0x06
#define X_NAK 0x15
@@ -48,5 +56,9 @@ void xmodem_clear_padding(uint8_t *buff);
#define NEW_FW_BASE (IFLASH_ADDR + (5*IFLASH_NB_OF_PAGES/8)*IFLASH_PAGE_SIZE)
#define NEW_FW_MAX_SIZE 196608
+#define FLASH_BUFFER 0x450000
+#define FLASH_BUFFER_END 0x480000
+
+#define NN_VERIFICATION_LEN 8
#endif /* FLASH_H_ */
\ No newline at end of file
diff --git a/ZodiacFX/src/http.c b/ZodiacFX/src/http.c
index 27d5d00..fca726f 100644
--- a/ZodiacFX/src/http.c
+++ b/ZodiacFX/src/http.c
@@ -53,6 +53,7 @@ extern uint32_t uid_buf[4]; // Unique identifier
extern struct tcp_pcb *tcp_pcb;
extern int OF_Version;
extern uint8_t shared_buffer[SHARED_BUFFER_LEN]; // SHARED_BUFFER_LEN must never be reduced below 2048
+extern int tcp_con_state; // Check connection state
extern struct ofp_flow_mod *flow_match10[MAX_FLOWS_10];
extern struct ofp13_flow_mod *flow_match13[MAX_FLOWS_13];
@@ -61,7 +62,10 @@ extern uint8_t *ofp13_oxm_inst[MAX_FLOWS_13];
extern uint16_t ofp13_oxm_inst_size[MAX_FLOWS_13];
extern struct flows_counter flow_counters[MAX_FLOWS_13];
extern struct flow_tbl_actions *flow_actions10[MAX_FLOWS_13];
+extern struct meter_entry13 *meter_entry[MAX_METER_13];
+extern struct meter_band_stats_array band_stats_array[MAX_METER_13];
extern int iLastFlow;
+extern int iLastMeter;
extern struct ofp10_port_stats phys10_port_stats[4];
extern struct ofp13_port_stats phys13_port_stats[4];
extern struct table_counter table_counters[MAX_TABLES];
@@ -71,31 +75,64 @@ extern int flash_write_page(uint8_t *flash_page);
// Local Variables
struct tcp_pcb *http_pcb;
-char http_msg[64]; // Buffer for HTTP message filtering
+static char http_msg[64]; // Buffer for HTTP message filtering
+static char post_msg[64]; // Buffer for HTTP message filtering
+static int page_ctr = 1;
+static int boundary_start = 1; // Check for start of data
+static uint8_t flowBase = 0; // Current set of flows to display
+static uint8_t meterBase = 0; // Current set of meters to display
+static struct tcp_pcb * upload_pcb; // Firmware upload connection check (pcb pointer)
+static int upload_port = 0;
+static int upload_timer = 0; // Timer for firmware upload timeout
+static struct http_conns http_conn[MAX_CONN]; // http connection status
+
+// Flag variables
+bool restart_required_outer = false;
+static bool restart_required = false; // Track if any configuration changes are pending a restart
static bool file_upload = false; // Multi-part firmware file upload flag
-bool reset_required;
+static bool post_pending = false;
static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
static err_t http_accept(void *arg, struct tcp_pcb *pcb, err_t err);
void http_send(char *buffer, struct tcp_pcb *pcb, bool out);
+static err_t http_sent(void *arg, struct tcp_pcb *tpcb, uint16_t len);
+void http_close(struct tcp_pcb *pcb);
+
+static uint8_t upload_handler(char *payload, int len);
+// HTML resources
static uint8_t interfaceCreate_Frames(void);
static uint8_t interfaceCreate_Header(void);
static uint8_t interfaceCreate_Menu(void);
static uint8_t interfaceCreate_Home(void);
static uint8_t interfaceCreate_Upload(void);
+static uint8_t interfaceCreate_Upload_Status(uint8_t sel);
static uint8_t interfaceCreate_Display_Home(void);
static uint8_t interfaceCreate_Display_Ports(uint8_t step);
static uint8_t interfaceCreate_Display_OpenFlow(void);
static uint8_t interfaceCreate_Display_Flows(void);
+static uint8_t interfaceCreate_Display_Meters(void);
static uint8_t interfaceCreate_Config_Home(void);
static uint8_t interfaceCreate_Config_Network(void);
static uint8_t interfaceCreate_Config_VLANs(void);
static uint8_t interfaceCreate_Config_OpenFlow(void);
static uint8_t interfaceCreate_About(void);
+static uint8_t interfaceCreate_Restart(void);
-static uint8_t upload_handler(char *ppart, int len);
-static int page_ctr = 1;
+static uint8_t http_header[] = "HTTP/1.1 200 OK\r\n"\
+ "Connection: Keep-Alive\r\n"\
+ "Content-Type: text/html; charset=UTF-8\r\n\r\n";
+
+static uint8_t html_style_body[] = "body {"\
+ "overflow: auto;"\
+ "font-family:Sans-serif;"\
+ "line-height: 1.2em;"\
+ "font-size: 17px;"\
+ "margin-left: 20px;"\
+ "}";
+
+// Configuration functions
+static uint8_t Config_Network(char *payload, int len);
/*
@@ -133,15 +170,65 @@ static err_t http_accept(void *arg, struct tcp_pcb *pcb, err_t err)
tcp_recv(pcb, http_recv);
tcp_err(pcb, NULL);
tcp_poll(pcb, NULL, 4);
+ tcp_sent(pcb, http_sent);
return ERR_OK;
}
+/*
+* HTTP Sent callback function
+*
+* @param *arg - pointer the additional TCP args
+* @param *tcp_pcb - pointer the TCP session structure.
+*
+*/
+static err_t http_sent(void *arg, struct tcp_pcb *tpcb, uint16_t len)
+{
+ TRACE("http.c: [http_sent] %d bytes sent", len);
+ for(int i=0; i 3000) // 3s connection timeout
+ {
+ TRACE("http.c: pcb 0x%08x has timed out. Connection will be closed.", http_conn[i].attached_pcb);
+ http_close(http_conn[i].attached_pcb);
+ }
+ }
+ }
+ if(restart_required == true)
+ {
+ restart_required_outer = true;
+ //TRACE("http.c: restarting the Zodiac FX. Please reconnect.");
+ //for(int x = 0;x<100000;x++); // Let the above message get sent to the terminal before detaching
+ //udc_detach(); // Detach the USB device before restart
+ //rstc_start_software_reset(RSTC); // Software reset
+ //while (1);
+ }
+
+ return ERR_OK;
+}
+
/*
* HTTP receive function
*
*/
static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
-{
+{
+ // Local variables
int len;
int i = 0;
char *http_payload;
@@ -154,17 +241,117 @@ static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err
http_payload = (char*)p->payload;
len = p->tot_len;
+ TRACE("http.c: -- HTTP recv received %d/%d payload bytes in this pbuf", p->len, p->tot_len);
+ TRACE("http.c: -> pcb @ addr: 0x%08x, remote port %d", pcb, pcb->remote_port);
+
if(file_upload == true)
- {
+ {
+ TRACE("http.c: %d ms since last firmware packet received", (sys_get_ms() - upload_timer));
+
+ // Check upload timeout
+ if(upload_timer != 0 && sys_get_ms() - upload_timer > UPLOAD_TIMEOUT)
+ {
+ TRACE("http.c: firmware upload has timed out");
+
+ /* Header request check */
+ memset(&http_msg, 0, sizeof(http_msg)); // Clear HTTP message array
+
+ // Specified resource directly follows GET
+ i = 0;
+ while(i < 63 && (http_payload[i+5] != ' '))
+ {
+ http_msg[i] = http_payload[i+5]; // Offset http_payload to isolate resource
+ i++;
+ }
+
+ // The "upload failed" message does not need to show up in the header
+ if(strcmp(http_msg,"header.htm") != 0)
+ {
+ // Stop upload operation
+ upload_handler(NULL, 0); // Clean up upload operation
+ if(interfaceCreate_Upload_Status(2))
+ {
+ http_send(&shared_buffer, pcb, 1);
+ TRACE("http.c: Page sent successfully - %d bytes", strlen(shared_buffer));
+ }
+ else
+ {
+ TRACE("http.c: Unable to serve page - buffer at %d bytes", strlen(shared_buffer));
+ }
+ }
+ }
+
+ if(upload_pcb != pcb && upload_port != pcb->remote_port)
+ {
+ TRACE("http.c: incoming connection ignored - upload currently in progress");
+
+ /* Header request check */
+ memset(&http_msg, 0, sizeof(http_msg)); // Clear HTTP message array
+
+ // Specified resource directly follows GET
+ i = 0;
+ while(i < 63 && (http_payload[i+5] != ' '))
+ {
+ http_msg[i] = http_payload[i+5]; // Offset http_payload to isolate resource
+ i++;
+ }
+
+ // The "upload in progress" message does not need to show up in the header
+ if(strcmp(http_msg,"header.htm") != 0)
+ {
+ if(interfaceCreate_Upload_Status(4))
+ {
+ http_send(&shared_buffer, pcb, 1);
+ TRACE("http.c: Page sent successfully - %d bytes", strlen(shared_buffer));
+ }
+ else
+ {
+ TRACE("http.c: Unable to serve page - buffer at %d bytes", strlen(shared_buffer));
+ }
+ }
+
+ return ERR_OK;
+ }
+
+ // Update timer value (new firmware packet received)
+ upload_timer = sys_get_ms();
+
int ret = 0;
- int tst = 3000;
// Handle multi-part file data
ret = upload_handler(http_payload, len);
- while(tst)
+ if(ret == 2)
{
- tst--;
+ file_upload = false;
+ boundary_start = 1;
+ //flash_clear_gpnvm(1);
+ // upload check
+ if(verification_check() == SUCCESS)
+ {
+ upload_handler(NULL, 0); // Clean up upload operation
+ if(interfaceCreate_Upload_Status(1))
+ {
+ http_send(&shared_buffer, pcb, 1);
+ TRACE("http.c: Page sent successfully - %d bytes", strlen(shared_buffer));
+ }
+ else
+ {
+ TRACE("http.c: Unable to serve page - buffer at %d bytes", strlen(shared_buffer));
+ }
+ }
+ else
+ {
+ upload_handler(NULL, 0); // Clean up upload operation
+ if(interfaceCreate_Upload_Status(3))
+ {
+ http_send(&shared_buffer, pcb, 1);
+ TRACE("http.c: Page sent successfully - %d bytes", strlen(shared_buffer));
+ }
+ else
+ {
+ TRACE("http.c: Unable to serve page - buffer at %d bytes", strlen(shared_buffer));
+ }
+ }
}
- tst = 0; // _______________________________ for debug purposes
}
else
{
@@ -175,10 +362,10 @@ static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err
http_msg[i] = http_payload[i];
i++;
}
- TRACE("http.c: %s method received", http_msg);
if(strcmp(http_msg,"GET") == 0)
{
+ TRACE("http.c: GET method received");
memset(&http_msg, 0, sizeof(http_msg)); // Clear HTTP message array
// Specified resource directly follows GET
@@ -199,7 +386,7 @@ static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err
}
// Check resource & serve page
- if(http_msg[0] == '\0')
+ if(http_msg[0] == '\0' || strcmp(http_msg,"frames.html") == 0)
{
if(interfaceCreate_Frames())
{
@@ -318,6 +505,18 @@ static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err
TRACE("http.c: Unable to serve page - buffer at %d bytes", strlen(shared_buffer));
}
}
+ else if(strcmp(http_msg,"d_meters.htm") == 0)
+ {
+ if(interfaceCreate_Display_Meters())
+ {
+ http_send(&shared_buffer, pcb, 1);
+ TRACE("http.c: Page sent successfully - %d bytes", strlen(shared_buffer));
+ }
+ else
+ {
+ TRACE("http.c: Unable to serve page - buffer at %d bytes", strlen(shared_buffer));
+ }
+ }
else if(strcmp(http_msg,"cfg_home.htm") == 0)
{
if(interfaceCreate_Config_Home())
@@ -383,8 +582,10 @@ static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err
TRACE("http.c: resource doesn't exist:\"%s\"", http_msg);
}
}
- else if(strcmp(http_msg,"POST") == 0)
+
+ else if(strcmp(http_msg,"POST") == 0 && post_pending == false)
{
+ TRACE("http.c: POST method received");
memset(&http_msg, 0, sizeof(http_msg)); // Clear HTTP message array
// Specified resource directly follows POST
@@ -394,12 +595,24 @@ static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err
http_msg[i] = http_payload[i+6]; // Offset http_payload to isolate resource
i++;
}
+ memcpy(post_msg, http_msg, 64);
+ TRACE("http.c: request for %s", post_msg);
+ post_pending = true;
+ pbuf_free(p);
+ return ERR_OK;
+ }
+ else
+ {
+ TRACE("http.c: unknown HTTP method received");
+ }
- TRACE("http.c: request for %s", http_msg);
-
- if(strcmp(http_msg,"upload") == 0)
+
+ if(post_pending == true)
+ {
+ post_pending = false;
+ if(strcmp(post_msg,"upload") == 0)
{
- // Initialise flash programming
+ // Initialize flash programming
if(firmware_update_init())
{
TRACE("http.c: firmware update initialisation successful");
@@ -411,223 +624,42 @@ static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err
// All following packets will contain multi-part file data
file_upload = true;
+ // Store pcb pointer value for this connection
+ upload_pcb = pcb;
+ // Store remote port
+ upload_port = pcb->remote_port;
+ // Initialize timeout value
+ upload_timer = sys_get_ms();
+
+ upload_handler(http_payload, len);
}
- else if(strcmp(http_msg,"save_config") == 0)
+ else if(strcmp(post_msg,"save_config") == 0)
{
- memset(&http_msg, 0, sizeof(http_msg)); // Clear HTTP message array
-
- // Device Name
- pdat = strstr(http_payload, "wi_deviceName"); // Search for element
- if(pdat != NULL) // Check that element exists
- {
- pdat += (strlen("wi_deviceName")+1); // Data format: wi_deviceName=(name)
-
- i = 0;
- while(i < 63 && (pdat[i] != '&') && (pdat[i] >= 31) && (pdat[i] <= 122))
- {
- http_msg[i] = pdat[i]; // Store value of element
- i++;
- }
- if(pdat[i+1] == 'w') // Check that the next parameter directly follows the "&" at end of data
- {
- uint8_t namelen = strlen(http_msg);
- if (namelen > 15 ) namelen = 15; // Make sure name is less than 16 characters
- sprintf(Zodiac_Config.device_name, http_msg, namelen);
- TRACE("http.c: device name set to '%s'",Zodiac_Config.device_name);
- }
- else
- {
- TRACE("http.c: \"&\" cannot be used in device name");
- }
- }
- else
- {
- TRACE("http.c: no device name found");
- }
-
- memset(&http_msg, 0, sizeof(http_msg));
-
- // MAC Address
- pdat = strstr(http_payload, "wi_macAddress");
- if(pdat != NULL) // Check that element exists
- {
- pdat += (strlen("wi_macAddress")+1); // Data format: wi_deviceName=(name)
-
- i = 0;
- while(i < 63 && (pdat[i] != '&') && (pdat[i] >= 31) && (pdat[i] <= 122))
- {
- http_msg[i] = pdat[i]; // Store value of element
- i++;
- }
- if(pdat[i+1] == 'w')
- {
- int mac1,mac2,mac3,mac4,mac5,mac6;
- char decArr[18] = "";
- int j, k;
-
- if (strlen(http_msg) != 27 ) // Accounting for ":" as "%3A"
- {
- TRACE("http.c: incorrect MAC address format");
- return;
- }
-
- // Decode http string
- j = 0; k = 0;
- while(j < strlen(http_msg) && k < 18)
- {
- if(http_msg[j] == '%' && http_msg[j+1] == '3' && http_msg[j+2] == 'A')
- {
- decArr[k] = ':';
- j+=3; k++;
- }
- else
- {
- decArr[k] = http_msg[j];
- j++; k++;
- }
- }
-
- sscanf(decArr, "%x:%x:%x:%x:%x:%x", &mac1, &mac2, &mac3, &mac4, &mac5, &mac6);
- Zodiac_Config.MAC_address[0] = mac1;
- Zodiac_Config.MAC_address[1] = mac2;
- Zodiac_Config.MAC_address[2] = mac3;
- Zodiac_Config.MAC_address[3] = mac4;
- Zodiac_Config.MAC_address[4] = mac5;
- Zodiac_Config.MAC_address[5] = mac6;
- TRACE("http.c: MAC address set to %.2X:%.2X:%.2X:%.2X:%.2X:%.2X",Zodiac_Config.MAC_address[0], Zodiac_Config.MAC_address[1], Zodiac_Config.MAC_address[2], Zodiac_Config.MAC_address[3], Zodiac_Config.MAC_address[4], Zodiac_Config.MAC_address[5]);
- }
- else
- {
- TRACE("http.c: \"&\" cannot be used in form");
- }
- }
- else
- {
- TRACE("http.c: no MAC address found");
- }
-
- memset(&http_msg, 0, sizeof(http_msg));
-
- // IP Address
- pdat = strstr(http_payload, "wi_ipAddress");
- if(pdat != NULL) // Check that element exists
- {
- pdat += (strlen("wi_ipAddress")+1); // Data format: wi_deviceName=(name)
-
- i = 0;
- while(i < 63 && (pdat[i] != '&') && (pdat[i] >= 31) && (pdat[i] <= 122))
- {
- http_msg[i] = pdat[i]; // Store value of element
- i++;
- }
- if(pdat[i+1] == 'w')
- {
- int ip1,ip2,ip3,ip4;
- if (strlen(http_msg) > 15 )
- {
- TRACE("http.c: incorrect IP format");
- return;
- }
- sscanf(http_msg, "%d.%d.%d.%d", &ip1, &ip2,&ip3,&ip4);
- Zodiac_Config.IP_address[0] = ip1;
- Zodiac_Config.IP_address[1] = ip2;
- Zodiac_Config.IP_address[2] = ip3;
- Zodiac_Config.IP_address[3] = ip4;
- TRACE("http.c: IP address set to %d.%d.%d.%d" , Zodiac_Config.IP_address[0], Zodiac_Config.IP_address[1], Zodiac_Config.IP_address[2], Zodiac_Config.IP_address[3]);
- }
- else
- {
- TRACE("http.c: \"&\" cannot be used in form");
- }
- }
- else
- {
- TRACE("http.c: no IP address found");
- }
-
- memset(&http_msg, 0, sizeof(http_msg));
-
- // Netmask
- pdat = strstr(http_payload, "wi_netmask");
- if(pdat != NULL) // Check that element exists
- {
- pdat += (strlen("wi_netmask")+1); // Data format: wi_deviceName=(name)
-
- i = 0;
- while(i < 63 && (pdat[i] != '&') && (pdat[i] >= 31) && (pdat[i] <= 122))
- {
- http_msg[i] = pdat[i]; // Store value of element
- i++;
- }
- if(pdat[i+1] == 'w')
- {
- int nm1,nm2,nm3,nm4;
- if (strlen(http_msg) > 15 )
- {
- TRACE("http.c: incorrect netmask format");
- return;
- }
- sscanf(http_msg, "%d.%d.%d.%d", &nm1, &nm2,&nm3,&nm4);
- Zodiac_Config.netmask[0] = nm1;
- Zodiac_Config.netmask[1] = nm2;
- Zodiac_Config.netmask[2] = nm3;
- Zodiac_Config.netmask[3] = nm4;
- TRACE("http.c: netmask set to %d.%d.%d.%d" , Zodiac_Config.netmask[0], Zodiac_Config.netmask[1], Zodiac_Config.netmask[2], Zodiac_Config.netmask[3]);
- }
- else
- {
- TRACE("http.c: \"&\" cannot be used in form");
- }
- }
- else
+ if(Config_Network(http_payload, len) == SUCCESS)
{
- TRACE("http.c: no netmask found");
- }
-
- memset(&http_msg, 0, sizeof(http_msg));
+ TRACE("http.c: network configuration successful");
- // Gateway
- pdat = strstr(http_payload, "wi_gateway");
- if(pdat != NULL) // Check that element exists
- {
- pdat += (strlen("wi_gateway")+1); // Data format: wi_deviceName=(name)
-
- i = 0;
- while(i < 63 && (pdat[i] != '&') && (pdat[i] >= 31) && (pdat[i] <= 122))
+ // Send updated config page
+ if(interfaceCreate_Config_Network())
{
- http_msg[i] = pdat[i]; // Store value of element
- i++;
+ http_send(&shared_buffer, pcb, 1);
+ TRACE("http.c: updated page sent successfully - %d bytes", strlen(shared_buffer));
+ return SUCCESS;
}
-
- // No next 'w' character check as this is the last element
-
- int gw1,gw2,gw3,gw4;
- if (strlen(http_msg) > 15 )
+ else
{
- TRACE("http.c: incorrect gateway format");
- return;
+ TRACE("http.c: unable to serve updated page - buffer at %d bytes", strlen(shared_buffer));
+ return FAILURE;
}
- sscanf(http_msg, "%d.%d.%d.%d", &gw1, &gw2,&gw3,&gw4);
- Zodiac_Config.gateway_address[0] = gw1;
- Zodiac_Config.gateway_address[1] = gw2;
- Zodiac_Config.gateway_address[2] = gw3;
- Zodiac_Config.gateway_address[3] = gw4;
- TRACE("http.c: gateway set to %d.%d.%d.%d" , Zodiac_Config.gateway_address[0], Zodiac_Config.gateway_address[1], Zodiac_Config.gateway_address[2], Zodiac_Config.gateway_address[3]);
}
else
{
- TRACE("http.c: no gateway address found");
+ TRACE("http.c: ERROR: network configuration failed");
}
-
- // Save configuration to EEPROM
- eeprom_write();
- TRACE("http.c: config written to EEPROM");
-
- // Set update required flag
- reset_required = true;
-
- // Send updated config page
- if(interfaceCreate_Config_Network())
+ }
+ else if(strcmp(post_msg,"btn_restart") == 0)
+ {
+ if(interfaceCreate_Restart())
{
http_send(&shared_buffer, pcb, 1);
TRACE("http.c: updated page sent successfully - %d bytes", strlen(shared_buffer));
@@ -636,24 +668,9 @@ static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err
{
TRACE("http.c: unable to serve updated page - buffer at %d bytes", strlen(shared_buffer));
}
-
- // Send updated header page (with restart button)
-
- // ***** Placeholder until frame refresh targeting is implemented
- //
- //
- //
-
+ restart_required = true;
}
- else if(strcmp(http_msg,"btn_restart") == 0)
- {
- TRACE("http.c: restarting the Zodiac FX. Please reconnect.");
- for(int x = 0;x<100000;x++); // Let the above message get sent to the terminal before detaching
- udc_detach(); // Detach the USB device before restart
- rstc_start_software_reset(RSTC); // Software reset
- while (1);
- }
- else if(strcmp(http_msg,"btn_default") == 0)
+ else if(strcmp(post_msg,"btn_default") == 0)
{
TRACE("http.c: restoring factory settings");
@@ -710,7 +727,7 @@ static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err
rstc_start_software_reset(RSTC); // Software reset
while (1);
}
- else if(strcmp(http_msg,"save_ports") == 0)
+ else if(strcmp(post_msg,"save_ports") == 0)
{
// Save VLAN port associations
@@ -820,16 +837,59 @@ static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err
TRACE("http.c: unable to serve updated page - buffer at %d bytes", strlen(shared_buffer));
}
}
- else if(strcmp(http_msg,"btn_ofNext") == 0)
+ else if(strcmp(post_msg,"btn_ofPage") == 0)
{
-
- }
- else if(strcmp(http_msg,"btn_ofPrev") == 0)
- {
-
+ // Display: Flows, Previous and Next flow page buttons
+
+ if(strstr(http_payload, "btn_ofNext") != NULL) // Check that element exists
+ {
+ TRACE("http.c: request for next page of flows");
+ TRACE("http.c: current flowBase: %d; current iLastFlow: %d;", flowBase, iLastFlow)
+ if(flowBase < iLastFlow-FLOW_DISPLAY_LIMIT)
+ {
+ // Increment flow base (display next set on page send)
+ flowBase += FLOW_DISPLAY_LIMIT;
+ TRACE("http.c: new flowBase: %d; current iLastFlow: %d;", flowBase, iLastFlow)
+ }
+ else
+ {
+ TRACE("http.c: flowBase already reaches end - NOT incremented")
+ }
+ }
+ else if(strstr(http_payload, "btn_ofPrev") != NULL)
+ {
+ TRACE("http.c: request for previous page of flows");
+ TRACE("http.c: current flowBase: %d; current iLastFlow: %d;", flowBase, iLastFlow)
+ if(flowBase >= FLOW_DISPLAY_LIMIT)
+ {
+ // Decrement flow base (display previous set on page send)
+ flowBase -= FLOW_DISPLAY_LIMIT;
+ TRACE("http.c: new flowBase: %d; current iLastFlow: %d;", flowBase, iLastFlow)
+ }
+ else
+ {
+ TRACE("http.c: flowBase already at start - NOT decremented")
+ }
+ }
+ else
+ {
+ TRACE("http.c: ERROR: invalid request");
+ }
+
+ // Send updated page
+ if(interfaceCreate_Display_Flows())
+ {
+ http_send(&shared_buffer, pcb, 1);
+ TRACE("http.c: updated page sent successfully - %d bytes", strlen(shared_buffer));
+ }
+ else
+ {
+ TRACE("http.c: unable to serve updated page - buffer at %d bytes", strlen(shared_buffer));
+ }
}
- else if(strcmp(http_msg,"btn_ofClear") == 0)
+ else if(strcmp(post_msg,"btn_ofClear") == 0)
{
+ // Display: Flows
// Clear the flow table
TRACE("http.c: clearing flow table, %d flow deleted.\r\n", iLastFlow);
clear_flows();
@@ -845,8 +905,60 @@ static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err
TRACE("http.c: unable to serve updated page - buffer at %d bytes", strlen(shared_buffer));
}
}
- else if(strcmp(http_msg,"save_vlan") == 0)
+ else if(strcmp(post_msg,"btn_meterPage") == 0)
+ {
+ // Display: Meters, Previous and Next meter page buttons
+
+ if(strstr(http_payload, "btn_meterNext") != NULL) // Check that element exists
+ {
+ TRACE("http.c: request for next page of meters");
+ TRACE("http.c: current meterBase: %d; current iLastMeter: %d;", meterBase, iLastMeter)
+ if(meterBase < iLastMeter-METER_DISPLAY_LIMIT)
+ {
+ // Increment flow base (display next set on page send)
+ meterBase += METER_DISPLAY_LIMIT;
+ TRACE("http.c: new meterBase: %d; current iLastMeter: %d;", meterBase, iLastMeter)
+ }
+ else
+ {
+ TRACE("http.c: meterBase already reaches end - NOT incremented")
+ }
+ }
+ else if(strstr(http_payload, "btn_meterPrev") != NULL)
+ {
+ TRACE("http.c: request for previous page of meters");
+ TRACE("http.c: current meterBase: %d; current iLastMeter: %d;", meterBase, iLastMeter)
+ if(meterBase >= METER_DISPLAY_LIMIT)
+ {
+ // Decrement meter base (display previous set on page send)
+ meterBase -= METER_DISPLAY_LIMIT;
+ TRACE("http.c: new meterBase: %d; current iLastMeter: %d;", meterBase, iLastMeter)
+ }
+ else
+ {
+ TRACE("http.c: meterBase already at start - NOT decremented")
+ }
+ }
+ else
+ {
+ TRACE("http.c: ERROR: invalid request");
+ }
+
+ // Send updated page
+ if(interfaceCreate_Display_Meters())
+ {
+ http_send(&shared_buffer, pcb, 1);
+ TRACE("http.c: updated page sent successfully - %d bytes", strlen(shared_buffer));
+ }
+ else
+ {
+ TRACE("http.c: unable to serve updated page - buffer at %d bytes", strlen(shared_buffer));
+ }
+ }
+ else if(strcmp(post_msg,"save_vlan") == 0)
{
+ // Config: VLANs, Add and Delete buttons
+
memset(&http_msg, 0, sizeof(http_msg)); // Clear HTTP message array
// Search for btn=
@@ -1024,8 +1136,10 @@ static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err
TRACE("http.c: unable to serve updated page - buffer at %d bytes", strlen(shared_buffer));
}
}
- else if(strcmp(http_msg,"save_of") == 0)
+ else if(strcmp(post_msg,"save_of") == 0)
{
+ // Config: OpenFlow, Save OpenFlow configuration
+
// Controller IP Address
memset(&http_msg, 0, sizeof(http_msg));
pdat = strstr(http_payload, "wi_ofIP");
@@ -1194,10 +1308,14 @@ static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err
TRACE("http.c: unknown request: \"%s\"", http_msg);
}
}
- else
- {
- TRACE("http.c: WARNING: unknown HTTP method received");
- }
+
+ }
+ }
+ else
+ {
+ if(err != ERR_OK)
+ {
+ TRACE("http.c: receive error - %d", err);
}
}
@@ -1208,14 +1326,13 @@ static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err
TRACE("http.c: Closing TCP connection.");
tcp_close(pcb);
}
-
return ERR_OK;
}
/*
* HTTP Send function
*
-* Parameter:
+* Parameters:
* out - specify whether TCP packet should be sent
*/
void http_send(char *buffer, struct tcp_pcb *pcb, bool out)
@@ -1231,208 +1348,705 @@ void http_send(char *buffer, struct tcp_pcb *pcb, bool out)
{
// Write data to tcp buffer
err = tcp_write(pcb, buffer, len, TCP_WRITE_FLAG_COPY + TCP_WRITE_FLAG_MORE);
- TRACE("http.c: sending %d bytes to TCP stack, %d REMAINING in buffer", len, (buf_size - len));
+ TRACE("http.c: tcp buffer %d/%d", len, buf_size);
- // Check if more data needs to be written
- if(out == true)
+ // Check if data is a part of a larger write
+ for(int i=0; i0)
{
py--;
- if((*py) == '\x0d' && (*(py+1)) == '\x0a' && (*(py+2)) == '\x2d' && (*(py+3)) == '\x2d')
+ // Latch onto '----' ("----[boundary ID]")
+ if((*(py-1)) == '\x2d' && (*(py-2)) == '\x2d' && (*(py-3)) == '\x2d' && (*(py-4)) == '\x2d')
{
- i = 0;
- // 'i' will be decremented to -1 if this line is run
+ // Store the discovered boundary
+ char tmpID[BOUNDARY_MAX_LEN] = {0};
+ int z = 0;
+ while(z < BOUNDARY_MAX_LEN && *(py+z) != '\x2d' && *(py+z) != '\x0d' && *(py+z) != '\x0a')
+ {
+ tmpID[z] = *(py+z);
+ z++;
+ }
+
+ TRACE("http.c: discovered boundary ID : %s", tmpID);
+
+ // Match the boundary ID with stored ID
+ if(strcmp(tmpID, boundary_ID) == 0)
+ {
+ TRACE("http.c: boundary IDs match");
+ TRACE("http.c: moving data end pointer");
+ // Traverse through the preceding newline characters
+ while(*(py-1) == '\x0d' || *(py-1) == '\x0a' || *(py-1) == '\x2d')
+ {
+ py--;
+ }
+
+ i = 0;
+ // 'i' will be decremented to -1 if this line is run
+ }
+ else
+ {
+ TRACE("http.c: boundary IDs do not match");
+ i = 1;
+ // 'i' will be decremented to 0 if this line is run
+ }
}
i--;
}
+
if(i == 0)
{
TRACE("http.c: ending boundary not found - ending data is valid");
+
+ // Return ending pointer to the end
+ py = payload + len;
}
else
{
TRACE("http.c: ending boundary found");
-
- // Return ending pointer to the end
- py = ppart + len;
-
final = 1;
}
- // Write data
+ // Get length of uploaded part
+ data_len = py - px;
+
+ // Check if any existing data needs to be handled
if(saved_bytes)
{
- // Fill in unwritten page (if it exists)
+ TRACE("http.c: %d saved bytes need to be cleared", saved_bytes);
+
if(final)
{
- while(saved_bytes < 512 && handled_bytes < len)
+ /* Final page needs to be written */
+
+ // Fill 512-byte array
+ while(saved_bytes < IFLASH_PAGE_SIZE)
{
- page[saved_bytes] = *px;
- px++;
+ if(px < py)
+ {
+ // Write data
+ page[saved_bytes] = *px;
+ px++;
+ handled_bytes++;
+ }
+ else
+ {
+ // Append 0xFF
+ page[saved_bytes] = 0xFF;
+ }
+
saved_bytes++;
- handled_bytes++;
+ }
+
+ // Write data to page
+ if(flash_write_page(&page))
+ {
+ TRACE("http.c: final firmware page written successfully");
+ page_ctr++;
+ }
+ else
+ {
+ TRACE("http.c: final firmware page write FAILED");
}
}
- else
+ else if(saved_bytes + len < IFLASH_PAGE_SIZE)
{
- while(saved_bytes < 512)
+ int max_len = saved_bytes + len;
+ // Fill existing partially-complete page with new data
+ while(saved_bytes < max_len && handled_bytes < len)
{
page[saved_bytes] = *px;
- px++;
+ if(px < py)
+ {
+ px++;
+ }
+ else
+ {
+ TRACE("http.c: ERROR - multi-part start pointer has passed the end pointer");
+ }
saved_bytes++;
handled_bytes++;
}
- }
-
- // Write data to page
- if(flash_write_page(&page)) // ___________________ CHECK
- {
- TRACE("http.c: firmware page written successfully (%02d)", page_ctr);
- page_ctr++;
+
+ // Handle edge-case
+ TRACE("http.c: unable to fill a complete page - skipping page write");
+ TRACE("http.c: %d bytes saved", saved_bytes);
+
+ total_handled_bytes += handled_bytes;
+ return 1;
}
else
{
- TRACE("http.c: firmware page write FAILED (%02d)", page_ctr);
+ // Fill existing partially-complete page with new data
+ while(saved_bytes < IFLASH_PAGE_SIZE && handled_bytes < len)
+ {
+ page[saved_bytes] = *px;
+ if(px < py)
+ {
+ px++;
+ }
+ else
+ {
+ TRACE("http.c: ERROR - multi-part start pointer has passed the end pointer");
+ }
+ saved_bytes++;
+ handled_bytes++;
+ }
+
+ // Write data to page
+ if(flash_write_page(&page))
+ {
+ TRACE("http.c: firmware page written successfully");
+ page_ctr++;
+ }
+ else
+ {
+ TRACE("http.c: firmware page write FAILED");
+ }
}
-
- memset(&page, 0, 512);
+
+ // Saved bytes have been handled - clear the counter
saved_bytes = 0;
+
+ TRACE("http.c: saved bytes have been cleared");
+ TRACE("http.c: handled_bytes: %04d, data_len: %04d", handled_bytes, data_len);
}
-
- if(handled_bytes < len)
- {
- int j;
- // Check for final page of data
- if(final)
+ while(handled_bytes < data_len)
+ {
+ if(data_len - handled_bytes >= IFLASH_PAGE_SIZE)
{
- j = 0;
- while(px < py)
+ // Fill 512-byte array
+ int j = 0;
+ while(j < IFLASH_PAGE_SIZE)
{
page[j] = *px;
- px++;
+ if(px < py)
+ {
+ px++;
+ }
+ else
+ {
+ TRACE("http.c: ERROR - multi-part start pointer has passed the end pointer");
+ }
j++;
handled_bytes++;
}
+
+ // Write to page
+ if(flash_write_page(&page))
+ {
+ TRACE("http.c: firmware page written successfully");
+ page_ctr++;
+ }
+ else
+ {
+ TRACE("http.c: firmware page write FAILED");
+ }
}
-
- // Write full pages
- while(len - handled_bytes >= 512)
+ else if(!final)
{
- j = 0;
- while(j < 512)
+ /* Data needs to be saved */
+ TRACE("http.c: data needs to be saved");
+
+ // Save leftover into page array for next run-through
+ int j = 0;
+ while(handled_bytes < data_len)
{
- page[j] = *px; // Store value of element
- px++;
+ page[j] = *px;
+ if(px < py)
+ {
+ px++;
+ }
+ else
+ {
+ TRACE("http.c: ERROR - multi-part start pointer has passed the end pointer");
+ }
j++;
handled_bytes++;
+ saved_bytes++;
}
-
- // Write data to page
- if(flash_write_page(&page)) // ___________________ CHECK
+
+ TRACE("http.c: %d bytes saved", saved_bytes);
+ }
+ else
+ {
+ /* Final page needs to be written */
+
+ // Fill 512-byte array
+ int j = 0;
+ while(j < IFLASH_PAGE_SIZE)
+ {
+ if(px < py)
+ {
+ // Write data
+ page[j] = *px;
+ px++;
+ handled_bytes++;
+ }
+ else
+ {
+ // Append 0xFF
+ page[j] = 0xFF;
+ }
+
+ j++;
+ }
+
+ // Write to page
+ if(flash_write_page(&page))
{
- TRACE("http.c: firmware page written successfully (%02d)", page_ctr);
+ TRACE("http.c: final page written successfully");
page_ctr++;
}
else
{
- TRACE("http.c: firmware page write FAILED (%02d)", page_ctr);
+ TRACE("http.c: final page write FAILED");
+ }
+ }
+
+ TRACE("http.c: handled_bytes: %04d, data_len: %04d", handled_bytes, data_len);
+ }
+
+ total_handled_bytes += handled_bytes;
+ TRACE("http.c: total_handled_bytes: %d", total_handled_bytes);
+
+ if(final)
+ {
+ return 2;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+static uint8_t Config_Network(char *payload, int len)
+{
+ int i = 0;
+ char *pdat;
+ payload[len] = '&';
+
+ memset(&http_msg, 0, sizeof(http_msg)); // Clear HTTP message array
+
+ // Device Name
+ pdat = strstr(payload, "wi_deviceName"); // Search for element
+ if(pdat != NULL) // Check that element exists
+ {
+ pdat += (strlen("wi_deviceName")+1); // Data format: wi_deviceName=(name)
+
+ i = 0;
+ while(i < 63 && (pdat[i] != '&') && (pdat[i] >= 31) && (pdat[i] <= 122))
+ {
+ http_msg[i] = pdat[i]; // Store value of element
+ i++;
+ }
+ if(pdat[i+1] == 'w') // Check that the next parameter directly follows the "&" at end of data
+ {
+ uint8_t namelen = strlen(http_msg);
+ if (namelen > 15 ) namelen = 15; // Make sure name is less than 16 characters
+ sprintf(Zodiac_Config.device_name, http_msg, namelen);
+ TRACE("http.c: device name set to '%s'",Zodiac_Config.device_name);
+ }
+ else
+ {
+ TRACE("http.c: \"&\" cannot be used in device name");
+ }
+ }
+ else
+ {
+ TRACE("http.c: no device name found");
+ }
+
+ memset(&http_msg, 0, sizeof(http_msg));
+
+ // MAC Address
+ pdat = strstr(payload, "wi_macAddress");
+ if(pdat != NULL) // Check that element exists
+ {
+ pdat += (strlen("wi_macAddress")+1); // Data format: wi_deviceName=(name)
+
+ i = 0;
+ while(i < 63 && (pdat[i] != '&') && (pdat[i] >= 31) && (pdat[i] <= 122))
+ {
+ http_msg[i] = pdat[i]; // Store value of element
+ i++;
+ }
+ if(pdat[i+1] == 'w')
+ {
+ int mac1,mac2,mac3,mac4,mac5,mac6;
+ char decArr[18] = "";
+ int j, k;
+
+ if (strlen(http_msg) != 27 ) // Accounting for ":" as "%3A"
+ {
+ TRACE("http.c: incorrect MAC address format");
+ return;
+ }
+
+ // Decode http string
+ j = 0; k = 0;
+ while(j < strlen(http_msg) && k < 18)
+ {
+ if(http_msg[j] == '%' && http_msg[j+1] == '3' && http_msg[j+2] == 'A')
+ {
+ decArr[k] = ':';
+ j+=3; k++;
+ }
+ else
+ {
+ decArr[k] = http_msg[j];
+ j++; k++;
+ }
}
- memset(&page, 0, 512);
+ sscanf(decArr, "%x:%x:%x:%x:%x:%x", &mac1, &mac2, &mac3, &mac4, &mac5, &mac6);
+ Zodiac_Config.MAC_address[0] = mac1;
+ Zodiac_Config.MAC_address[1] = mac2;
+ Zodiac_Config.MAC_address[2] = mac3;
+ Zodiac_Config.MAC_address[3] = mac4;
+ Zodiac_Config.MAC_address[4] = mac5;
+ Zodiac_Config.MAC_address[5] = mac6;
+ TRACE("http.c: MAC address set to %.2X:%.2X:%.2X:%.2X:%.2X:%.2X",Zodiac_Config.MAC_address[0], Zodiac_Config.MAC_address[1], Zodiac_Config.MAC_address[2], Zodiac_Config.MAC_address[3], Zodiac_Config.MAC_address[4], Zodiac_Config.MAC_address[5]);
}
+ else
+ {
+ TRACE("http.c: \"&\" cannot be used in form");
+ }
+ }
+ else
+ {
+ TRACE("http.c: no MAC address found");
+ }
+
+ memset(&http_msg, 0, sizeof(http_msg));
+
+ // IP Address
+ pdat = strstr(payload, "wi_ipAddress");
+ if(pdat != NULL) // Check that element exists
+ {
+ pdat += (strlen("wi_ipAddress")+1); // Data format: wi_deviceName=(name)
- // Save unwritten data
- j = 0;
- while(handled_bytes < len)
+ i = 0;
+ while(i < 63 && (pdat[i] != '&') && (pdat[i] >= 31) && (pdat[i] <= 122))
{
- page[j] = *px; // Store value of element
- px++;
- j++;
- handled_bytes++;
+ http_msg[i] = pdat[i]; // Store value of element
+ i++;
+ }
+ if(pdat[i+1] == 'w')
+ {
+ int ip1,ip2,ip3,ip4;
+ if (strlen(http_msg) > 15 )
+ {
+ TRACE("http.c: incorrect IP format");
+ return;
+ }
+ sscanf(http_msg, "%d.%d.%d.%d", &ip1, &ip2,&ip3,&ip4);
+ Zodiac_Config.IP_address[0] = ip1;
+ Zodiac_Config.IP_address[1] = ip2;
+ Zodiac_Config.IP_address[2] = ip3;
+ Zodiac_Config.IP_address[3] = ip4;
+ TRACE("http.c: IP address set to %d.%d.%d.%d" , Zodiac_Config.IP_address[0], Zodiac_Config.IP_address[1], Zodiac_Config.IP_address[2], Zodiac_Config.IP_address[3]);
+ }
+ else
+ {
+ TRACE("http.c: \"&\" cannot be used in form");
}
+ }
+ else
+ {
+ TRACE("http.c: no IP address found");
+ }
+
+ memset(&http_msg, 0, sizeof(http_msg));
+
+ // Netmask
+ pdat = strstr(payload, "wi_netmask");
+ if(pdat != NULL) // Check that element exists
+ {
+ pdat += (strlen("wi_netmask")+1); // Data format: wi_deviceName=(name)
- if(px > py)
+ i = 0;
+ while(i < 63 && (pdat[i] != '&') && (pdat[i] >= 31) && (pdat[i] <= 122))
{
- TRACE("http.c: ERROR - pointer has passed the data");
- return 0;
+ http_msg[i] = pdat[i]; // Store value of element
+ i++;
+ }
+ if(pdat[i+1] == 'w')
+ {
+ int nm1,nm2,nm3,nm4;
+ if (strlen(http_msg) > 15 )
+ {
+ TRACE("http.c: incorrect netmask format");
+ return;
+ }
+ sscanf(http_msg, "%d.%d.%d.%d", &nm1, &nm2,&nm3,&nm4);
+ Zodiac_Config.netmask[0] = nm1;
+ Zodiac_Config.netmask[1] = nm2;
+ Zodiac_Config.netmask[2] = nm3;
+ Zodiac_Config.netmask[3] = nm4;
+ TRACE("http.c: netmask set to %d.%d.%d.%d" , Zodiac_Config.netmask[0], Zodiac_Config.netmask[1], Zodiac_Config.netmask[2], Zodiac_Config.netmask[3]);
+ }
+ else
+ {
+ TRACE("http.c: \"&\" cannot be used in form");
}
}
+ else
+ {
+ TRACE("http.c: no netmask found");
+ }
- if(final)
+ memset(&http_msg, 0, sizeof(http_msg));
+
+ // Gateway
+ pdat = strstr(payload, "wi_gateway");
+ if(pdat != NULL) // Check that element exists
{
- return 2;
+ pdat += (strlen("wi_gateway")+1); // Data format: wi_deviceName=(name)
+
+ i = 0;
+ while(i < 63 && (pdat[i] != '&') && (pdat[i] >= 31) && (pdat[i] <= 122))
+ {
+ http_msg[i] = pdat[i]; // Store value of element
+ i++;
+ }
+
+ // No next 'w' character check as this is the last element
+
+ int gw1,gw2,gw3,gw4;
+ if (strlen(http_msg) > 15 )
+ {
+ TRACE("http.c: incorrect gateway format");
+ return;
+ }
+ sscanf(http_msg, "%d.%d.%d.%d", &gw1, &gw2,&gw3,&gw4);
+ Zodiac_Config.gateway_address[0] = gw1;
+ Zodiac_Config.gateway_address[1] = gw2;
+ Zodiac_Config.gateway_address[2] = gw3;
+ Zodiac_Config.gateway_address[3] = gw4;
+ TRACE("http.c: gateway set to %d.%d.%d.%d" , Zodiac_Config.gateway_address[0], Zodiac_Config.gateway_address[1], Zodiac_Config.gateway_address[2], Zodiac_Config.gateway_address[3]);
}
else
{
- return 1;
+ TRACE("http.c: no gateway address found");
}
+
+ // Save configuration to EEPROM
+ eeprom_write();
+ TRACE("http.c: config written to EEPROM");
+
+ return SUCCESS;
+
+ // Send updated header page (with restart button)
+
+ // ***** Placeholder until frame refresh targeting is implemented
+ //
+ //
+ //
}
/*
@@ -1442,9 +2056,7 @@ static uint8_t upload_handler(char *ppart, int len)
static uint8_t interfaceCreate_Frames(void)
{
// Format HTTP response
- sprintf(shared_buffer,"HTTP/1.1 200 OK\r\n");
- strcat(shared_buffer,"Connection: close\r\n");
- strcat(shared_buffer,"Content-Type: text/html; charset=UTF-8\r\n\r\n");
+ sprintf(shared_buffer, http_header);
// Send frames
strcat(shared_buffer, \
""\
@@ -1489,68 +2101,13 @@ static uint8_t interfaceCreate_Frames(void)
*/
static uint8_t interfaceCreate_Header(void)
{
- reset_required = true; // ***** Placeholder until frame refresh targeting is implemented
-
int hr = (totaltime/2)/3600;
int t = (totaltime/2)%3600;
int min = t/60;
// Send header
- if(reset_required == false)
- {
- if( snprintf(shared_buffer, SHARED_BUFFER_LEN,\
- ""\
- " "\
- ""\
- ""\
- ""\
- ""\
- ""\
- ""\
- ""\
- "Uptime: %02d:%02d"\
- "
"\
- ""\
- ""\
- , hr, min) < SHARED_BUFFER_LEN)
- {
- TRACE("http.c: html written to buffer");
- return 1;
- }
- else
- {
- TRACE("http.c: WARNING: html truncated to prevent buffer overflow");
- return 0;
- }
- }
- else if(reset_required == true)
- {
- if( snprintf(shared_buffer, SHARED_BUFFER_LEN,\
+ sprintf(shared_buffer, http_header);
+ if( snprintf(shared_buffer+strlen(shared_buffer), SHARED_BUFFER_LEN-strlen(shared_buffer),\
""\
" "\
""\
@@ -1593,7 +2150,7 @@ static uint8_t interfaceCreate_Header(void)
"Zodiac FX "\
""\
""\
- ""\
"
"\
@@ -1613,7 +2170,6 @@ static uint8_t interfaceCreate_Header(void)
return 0;
}
}
-}
/*
* Create and format HTML for menu page
@@ -1622,7 +2178,9 @@ static uint8_t interfaceCreate_Header(void)
static uint8_t interfaceCreate_Menu(void)
{
// Send menu
- if( snprintf(shared_buffer, SHARED_BUFFER_LEN,\
+ sprintf(shared_buffer, http_header);
+
+ if( snprintf(shared_buffer+strlen(shared_buffer), SHARED_BUFFER_LEN-strlen(shared_buffer),\
""\
""\
""\
@@ -1656,11 +2214,12 @@ static uint8_t interfaceCreate_Menu(void)
""\
""\
"Status "\
- //"Update f/w "
+ "Update f/w "
"Display "\
"Ports "\
"OpenFlow "\
"Flows "\
+ "Meters "\
"Config "\
"Network "\
"VLANs "\
@@ -1691,19 +2250,17 @@ static uint8_t interfaceCreate_Home(void)
int t = (totaltime/2)%3600;
int min = t/60;
- if( snprintf(shared_buffer, SHARED_BUFFER_LEN,\
+ sprintf(shared_buffer, http_header);
+
+ snprintf(shared_buffer+strlen(shared_buffer), SHARED_BUFFER_LEN-strlen(shared_buffer),\
""\
" "\
""\
""\
""\
""\
""\
@@ -1738,18 +2295,16 @@ static uint8_t interfaceCreate_Home(void)
*/
static uint8_t interfaceCreate_Upload(void)
{
- if( snprintf(shared_buffer, SHARED_BUFFER_LEN,\
+ sprintf(shared_buffer, http_header);
+
+ snprintf(shared_buffer+strlen(shared_buffer), SHARED_BUFFER_LEN-strlen(shared_buffer),\
""\
""\
""\
""\
""\
""\
@@ -1757,9 +2312,8 @@ static uint8_t interfaceCreate_Upload(void)
"Firmware Update "\
"
"\
""\
- "Browser firmware update is currently only supported in Chrome. "\
- "Do not attempt an update with an unsupported browser.
"\
- ""\
@@ -1777,24 +2331,126 @@ static uint8_t interfaceCreate_Upload(void)
}
}
+/*
+* Create and format HTML for firmware update status page
+*
+*/
+static uint8_t interfaceCreate_Upload_Status(uint8_t sel)
+{
+ if(sel == 1)
+ {
+ if( snprintf(shared_buffer, SHARED_BUFFER_LEN,\
+ ""\
+ ""\
+ ""\
+ ""\
+ ""\
+ ""\
+ ""\
+ "
Firmware Update "\
+ ""\
+ ""\
+ "Firmware upload successful. "\
+ "Zodiac FX will be updated on the next restart.
"\
+ ""\
+ ""\
+ ""\
+ ) < SHARED_BUFFER_LEN)
+ {
+ TRACE("http.c: html written to buffer");
+ return 1;
+ }
+ else
+ {
+ TRACE("http.c: WARNING: html truncated to prevent buffer overflow");
+ return 0;
+ }
+ }
+ else
+ {
+ snprintf(shared_buffer, SHARED_BUFFER_LEN,\
+ ""\
+ ""\
+ ""\
+ ""\
+ ""\
+ ""\
+ ""\
+ "
Firmware Update "\
+ ""\
+ ""\
+ );
+ if(sel == 2)
+ {
+ snprintf(shared_buffer+strlen(shared_buffer), SHARED_BUFFER_LEN-strlen(shared_buffer),\
+ "Firmware upload interrupted. Please try again. "\
+ );
+ }
+ else if(sel == 3)
+ {
+ snprintf(shared_buffer+strlen(shared_buffer), SHARED_BUFFER_LEN-strlen(shared_buffer),\
+ "
Firmware upload failed. Unable to verify firmware. Please try again, or check the integrity of the firmware. "\
+ );
+ }
+ else if(sel == 4)
+ {
+ snprintf(shared_buffer+strlen(shared_buffer), SHARED_BUFFER_LEN-strlen(shared_buffer),\
+ "
Firmware upload in progress. Please try again in 30 seconds. "\
+ );
+ }
+ else
+ {
+ snprintf(shared_buffer+strlen(shared_buffer), SHARED_BUFFER_LEN-strlen(shared_buffer),\
+ "
Firmware upload failed. Please try again. "\
+ );
+ }
+
+ if( snprintf(shared_buffer+strlen(shared_buffer), SHARED_BUFFER_LEN-strlen(shared_buffer),\
+ ""\
+ ""\
+ ) < SHARED_BUFFER_LEN)
+ {
+ TRACE("http.c: html written to buffer");
+ return 1;
+ }
+ else
+ {
+ TRACE("http.c: WARNING: html truncated to prevent buffer overflow");
+ return 0;
+ }
+ }
+}
+
/*
* Create and format HTML for display help page
*
*/
static uint8_t interfaceCreate_Display_Home(void)
{
- if( snprintf(shared_buffer, SHARED_BUFFER_LEN,\
+ sprintf(shared_buffer, http_header);
+
+ snprintf(shared_buffer+strlen(shared_buffer), SHARED_BUFFER_LEN-strlen(shared_buffer),\
""\
""\
"
"\
""\
""\
""\
@@ -1811,7 +2467,11 @@ static uint8_t interfaceCreate_Display_Home(void)
""\
"Flows "\
""\
- "View the current flows in the flow table. This page is currently limited to displaying a maximum of 5 flows."\
+ "View the current flows in the flow table. 4 flows are displayed per page."\
+ "
"\
+ "Meters "\
+ ""\
+ "View the current meters in the meter table. 3 meters are displayed per page. Up to 8 meters can be configured, with up to 3 meter bands each."\
"
"\
""\
""\
@@ -1863,20 +2523,18 @@ static uint8_t interfaceCreate_Display_Ports(uint8_t step)
vlCtr++;
}
}
+
+ sprintf(shared_buffer, http_header);
- snprintf(shared_buffer, SHARED_BUFFER_LEN,\
+ snprintf(shared_buffer+strlen(shared_buffer), SHARED_BUFFER_LEN-strlen(shared_buffer),\
""\
+ " "\
""\
""\
""\
""\
""\
@@ -1905,7 +2566,7 @@ static uint8_t interfaceCreate_Display_Ports(uint8_t step)
"Ports "\
""\
""\
- " "\
+ " "\
"Port 1 "\
"Port 2 "\
"Port 3 "\
@@ -2085,8 +2746,8 @@ static uint8_t interfaceCreate_Display_Ports(uint8_t step)
" "\
"
"\
" "\
- " "\
- " "\
+ " "\
+ " "\
""\
""\
""\
@@ -2164,8 +2825,8 @@ static uint8_t interfaceCreate_Display_Ports(uint8_t step)
""\
""\
" "\
- " "\
- " "\
+ " "\
+ " "\
""\
""\
""\
@@ -2206,11 +2867,7 @@ static uint8_t interfaceCreate_Display_OpenFlow(void)
// Status
char wi_ofStatus[15] = "";
- if (tcp_pcb->state != ESTABLISHED && Zodiac_Config.OFEnabled == OF_ENABLED)
- {
- snprintf(wi_ofStatus, 15, "Disconnected");
- }
- else if (tcp_pcb->state == ESTABLISHED && Zodiac_Config.OFEnabled == OF_ENABLED)
+ if (tcp_con_state == 1 && tcp_pcb->state == ESTABLISHED && Zodiac_Config.OFEnabled == OF_ENABLED)
{
snprintf(wi_ofStatus, 15, "Connected");
}
@@ -2220,7 +2877,7 @@ static uint8_t interfaceCreate_Display_OpenFlow(void)
}
else
{
- snprintf(wi_ofStatus, 15, "Error: unknown");
+ snprintf(wi_ofStatus, 15, "Disconnected");
}
// Version, Tables, Flows, Lookups, Matches
@@ -2267,25 +2924,25 @@ static uint8_t interfaceCreate_Display_OpenFlow(void)
snprintf(wi_ofVersion, 15, "Auto");
}
- if( snprintf(shared_buffer, SHARED_BUFFER_LEN,\
+ sprintf(shared_buffer, http_header);
+
+ snprintf(shared_buffer+strlen(shared_buffer), SHARED_BUFFER_LEN-strlen(shared_buffer),\
""\
+ " "\
""\
""\
""\
""\
""\
""\
"
OpenFlow Information "\
""\
- "