diff --git a/Makefile b/Makefile index abf61de..cb948f5 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ CONFIG_LOCATION = 458752 HTML_LOCATION = 262144 CC = sdcc -CC_FLAGS = -mmcs51 -Ihttpd -Iuip +CC_FLAGS = -mmcs51 -I. -Ihttpd -Iuip ASM = sdas8051 AFLAGS= -plosgff @@ -21,7 +21,7 @@ all: create_build_dir $(VERSION_HEADER) $(SUBDIRS) $(BUILDDIR)rtlplayground.bin create_build_dir: mkdir -p $(BUILDDIR) -SRCS = rtlplayground.c rtl837x_flash.c rtl837x_phy.c rtl837x_port.c cmd_parser.c html_data.c rtl837x_igmp.c rtl837x_stp.c machine.c +SRCS = rtlplayground.c rtl837x_flash.c rtl837x_phy.c rtl837x_port.c cmd_parser.c html_data.c rtl837x_igmp.c rtl837x_stp.c dhcp.c machine.c OBJS = ${SRCS:%.c=$(BUILDDIR)%.rel} OBJS += uip/$(BUILDDIR)/timer.rel uip/$(BUILDDIR)/uip-fw.rel uip/$(BUILDDIR)/uip-neighbor.rel uip/$(BUILDDIR)/uip-split.rel uip/$(BUILDDIR)/uip.rel uip/$(BUILDDIR)/uip_arp.rel uip/$(BUILDDIR)/uiplib.rel httpd/$(BUILDDIR)/httpd.rel httpd/$(BUILDDIR)/page_impl.rel @@ -59,17 +59,14 @@ $(BUILDDIR)%.rel: $(BUILDDIR)%.asm # mv -f $(addprefix $(basename $^), .lst .rel .sym) . $(BUILDDIR)rtlplayground.ihx: $(BUILDDIR)crtstart.rel $(OBJS) $(BUILDDIR)crc16.rel - $(CC) $(CC_FLAGS) -Wl-bHOME=${BOOTLOADER_ADDRESS} -Wl-bBANK1=0x14000 -Wl-r -o $@ $^ + $(CC) $(CC_FLAGS) -Wl-bHOME=${BOOTLOADER_ADDRESS} -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-r -o $@ $^ $(BUILDDIR)rtlplayground.img: $(BUILDDIR)rtlplayground.ihx objcopy --input-target=ihex -O binary $< $@ $(BUILDDIR)rtlplayground.bin: $(BUILDDIR)rtlplayground.img if [ -e $@ ]; then rm $@; fi - echo "0000000: 00 40" | xxd -r - $@ - cat $< >> $@ - truncate --size=16K $@ - dd if=$< skip=80 bs=1024 >>$@ + tools/$(BUILDDIR)imagebuilder -i $^ $@ tools/$(BUILDDIR)fileadder -a $(CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@ tools/$(BUILDDIR)fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -d html -p html_data $@ tools/$(BUILDDIR)crc_calculator -u $@ diff --git a/cmd_parser.c b/cmd_parser.c index 4a531fc..2e8f12e 100644 --- a/cmd_parser.c +++ b/cmd_parser.c @@ -13,6 +13,7 @@ #include "rtl837x_sfr.h" #include "rtl837x_stp.h" #include "rtl837x_igmp.h" +#include "dhcp.h" #include "uip/uip.h" #include "version.h" @@ -37,6 +38,8 @@ extern __xdata struct flash_region_t flash_region; extern __xdata char passwd[21]; +extern __xdata struct dhcp_state dhcp_state; + __xdata uint8_t vlan_names[VLAN_NAMES_SIZE]; __xdata uint16_t vlan_ptr; __xdata uint8_t gpio_last_value[8] = { 0 }; @@ -149,6 +152,7 @@ uint8_t atoi_hex(uint8_t idx) return ((h_idx + 1) >> 1); } + uint8_t atoi_short(register uint16_t *vlan, register uint8_t idx) { uint8_t err = 1; @@ -774,28 +778,64 @@ void cmd_parser(void) __banked } else if (cmd_compare(0, "mtu") && cmd_words_b[1] > 0) { parse_mtu(); } else if (cmd_compare(0, "ip")) { - print_string("Got ip command: "); - if (!parse_ip(cmd_words_b[1])) - uip_ipaddr(&uip_hostaddr, ip[0], ip[1], ip[2], ip[3]); - else - print_string("Invalid IP address\n"); - print_byte(ip[0]); print_byte(ip[1]); print_byte(ip[2]); print_byte(ip[3]); - write_char('\n'); + if (cmd_words_b[2] > 0 && cmd_compare(1, "dhcp")) { + dhcp_start(); + } else if (cmd_words_b[2] < 0) { + print_string("Current IP: "); + itoa(uip_hostaddr[0]); write_char('.'); itoa(uip_hostaddr[0] >> 8); write_char('.'); + itoa(uip_hostaddr[1]); write_char('.'); itoa(uip_hostaddr[1] >> 8); + if (dhcp_state.state == DHCP_LEASING) { + print_string(" (dhcp, renewal in sec: "); + print_short(dhcp_state.dhcp_timer); + write_char(')'); + } else { + print_string(" (static)"); + } + write_char('\n'); + } else { + if (dhcp_state.state) + dhcp_stop(); + if (!parse_ip(cmd_words_b[1])) { + uip_ipaddr(&uip_hostaddr, ip[0], ip[1], ip[2], ip[3]); + print_string("Setting ip: "); + itoa(ip[0]); write_char('.'); itoa(ip[1]); write_char('.'); + itoa(ip[2]); write_char('.'); itoa(ip[3]); write_char('\n'); + } else { + print_string("Invalid IP address\n"); + print_string("Error: ip [|dhcp]\n"); + print_string(" The dhcp option enables the dhcp client, calling ip without options prints the current IP\n"); + print_string(" Calling with a valid IP address will stop any ongoing dhcp client and set the IP address\n"); + } + } } else if (cmd_compare(0, "gw")) { - print_string("Got gw command: "); - if (!parse_ip(cmd_words_b[1])) - uip_ipaddr(&uip_draddr, ip[0], ip[1], ip[2], ip[3]); - else - print_string("Invalid IP address\n"); - print_byte(ip[0]); print_byte(ip[1]); print_byte(ip[2]); print_byte(ip[3]); + if (cmd_words_b[2] < 0) { + print_string("Current gw: "); + itoa(uip_draddr[0]); write_char('.'); itoa(uip_draddr[0] >> 8); write_char('.'); + itoa(uip_draddr[1]); write_char('.'); itoa(uip_draddr[1] >> 8); + } else { + if (!parse_ip(cmd_words_b[1])) + uip_ipaddr(&uip_draddr, ip[0], ip[1], ip[2], ip[3]); + else + print_string("Invalid IP address\n"); + print_string("Setting gw: "); + itoa(ip[0]); write_char('.'); itoa(ip[1]); write_char('.'); + itoa(ip[2]); write_char('.'); itoa(ip[3]); + } write_char('\n'); } else if (cmd_compare(0, "netmask")) { - print_string("Got netmask command: "); - if (!parse_ip(cmd_words_b[1])) - uip_ipaddr(&uip_netmask, ip[0], ip[1], ip[2], ip[3]); - else - print_string("Invalid IP address\n"); - print_byte(ip[0]);print_byte(ip[1]);print_byte(ip[2]);print_byte(ip[3]); + if (cmd_words_b[2] < 0) { + print_string("Current netmask: "); + itoa(uip_netmask[0]); write_char('.'); itoa(uip_netmask[0] >> 8); write_char('.'); + itoa(uip_netmask[1]); write_char('.'); itoa(uip_netmask[1] >> 8); + } else { + if (!parse_ip(cmd_words_b[1])) + uip_ipaddr(&uip_netmask, ip[0], ip[1], ip[2], ip[3]); + else + print_string("Invalid IP address\n"); + print_string("Setting netmask: "); + itoa(ip[0]); write_char('.'); itoa(ip[1]); write_char('.'); + itoa(ip[2]); write_char('.'); itoa(ip[3]); + } write_char('\n'); } else if (cmd_compare(0, "l2")) { if (cmd_words_b[1] > 0 && cmd_compare(1, "forget")) diff --git a/dhcp.c b/dhcp.c new file mode 100644 index 0000000..ed49b5e --- /dev/null +++ b/dhcp.c @@ -0,0 +1,391 @@ +/* + * This is a DHCP client implementation for the RTL837x-based switches + */ + +// #define REGDBG +// #define DEBUG + +#include +#include "rtl837x_sfr.h" +#include "rtl837x_common.h" +#include "dhcp.h" +#include "uip.h" +#include "uip/uip.h" + +extern __code struct uip_eth_addr uip_ethaddr; +__xdata struct dhcp_state dhcp_state; +__xdata uip_ipaddr_t server; + +#define DHCP_HW_TYPE_ETH 1 + +#define DHCP_SUBNET_MASK 1 +#define DHCP_SUBNET_MASK_LEN 4 +#define DHCP_ROUTER 3 +#define DHCP_ROUTER_LEN 4 +#define DHCP_DNS 6 +#define DHCP_DNS_LEN 4 +#define DHCP_BROADCAST 28 +#define DHCP_BROADCAST_LEN 4 +#define DHCP_SERVER_ID 54 +#define DHCP_SERVER_ID_LEN 4 +#define DHCP_MESSAGE_TYPE 53 +#define DHCP_MESSAGE_TYPE_LEN 1 +#define DHCP_MESSAGE_DISCOVER 1 +#define DHCP_MESSAGE_OFFER 2 +#define DHCP_MESSAGE_REQUEST 3 +#define DHCP_MESSAGE_ACK 5 +#define DHCP_LEASE 51 +#define DHCP_LEASE_LEN 4 +#define DHCP_RENEWAL 58 +#define DHCP_RENEWAL_LEN 4 +#define DHCP_REBIND 59 +#define DHCP_REBIND_LEN 4 +#define DHCP_CLIENT_ID 61 +#define DHCP_CLIENT_ID_LEN 7 +#define DHCP_REQUEST_IP 50 +#define DHCP_REQUEST_IP_LEN 4 +#define DHCP_PARAMS 55 +#define DHCP_PARAM_SUBNET 1 +#define DHCP_PARAM_ROUTER 3 +#define DHCP_PARAM_DNS 6 +#define DHCP_END 255 + +#pragma codeseg BANK2 +#pragma constseg BANK2 + +struct dhcp_pkt { + uint8_t type; + uint8_t hw; + uint8_t hw_len; + uint8_t hops; + uint32_t tid; + uint16_t delay; + uint16_t flags; + uint8_t client_ip[4]; + uint8_t your_ip[4]; + uint8_t next_server_ip[4]; + uint8_t relay_ip[4]; + uint8_t client_addr[6]; + uint8_t client_pad[10]; + uint8_t server_name[64]; + uint8_t file[128]; + uint8_t cookie[4]; +}; + +/* +#define DHCP_P ((__xdata struct dhcp_pkt *)&uip_buf[RTL_TAG_SIZE + VLAN_TAG_SIZE]) +#define DHCP_OPT ((__xdata uint8_t *)&uip_buf[RTL_TAG_SIZE + VLAN_TAG_SIZE + sizeof (struct dhcp_pkt)]) +*/ + +#define DHCP_P ((__xdata struct dhcp_pkt *)uip_appdata) +#define DHCP_OPT ((__xdata uint8_t *)(uip_appdata) + sizeof (struct dhcp_pkt)) + +__xdata uint32_t long_value; + + +void dhcp_print_ip(uint8_t *a) +{ + itoa(a[0]); write_char('.'); + itoa(a[1]); write_char('.'); + itoa(a[2]); write_char('.'); + itoa(a[3]); +} + + +void dhcp_prepare_request(void) +{ + DHCP_P->type = 1; + DHCP_P->hw = DHCP_HW_TYPE_ETH; + DHCP_P->hw_len = 6; + DHCP_P->hops = 0; + + DHCP_P->tid = HTONS(dhcp_state.transaction_id); + DHCP_P->delay = HTONS(0); + DHCP_P->flags = 0; + // Clear fields client_ip to bootp_file + memset(DHCP_P->client_ip, 0, 224); + memcpyc(DHCP_P->client_addr, uip_ethaddr.addr, 6); + DHCP_P->cookie[0] = 0x63; + DHCP_P->cookie[1] = 0x82; + DHCP_P->cookie[2] = 0x53; + DHCP_P->cookie[3] = 0x63; +} + + +void dhcp_addopt_client_id(void) +{ + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_CLIENT_ID; + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_CLIENT_ID_LEN; + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_HW_TYPE_ETH; + memcpyc(&DHCP_OPT[dhcp_state.opt_ptr], uip_ethaddr.addr, 6); + dhcp_state.opt_ptr += 6; +} + + +void dhcp_addopt_request_ip(void) +{ + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_REQUEST_IP; + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_REQUEST_IP_LEN; + DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[0]; + DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[1]; + DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[2]; + DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[3]; + memcpyc(&DHCP_OPT[dhcp_state.opt_ptr], uip_ethaddr.addr, 4); +} + + +void dhcp_addopt_server_id(void) +{ + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_SERVER_ID; + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_SERVER_ID_LEN; + DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[0]; + DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[1]; + DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[2]; + DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[3]; + memcpyc(&DHCP_OPT[dhcp_state.opt_ptr], uip_ethaddr.addr, 4); +} + + +void dhcp_send_discover(void) +{ + print_string("dhcp_send_discover called\n"); + dhcp_prepare_request(); + + dhcp_state.opt_ptr = 0; + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_MESSAGE_TYPE; + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_MESSAGE_TYPE_LEN; + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_MESSAGE_DISCOVER; + + dhcp_addopt_client_id(); + dhcp_addopt_request_ip(); + + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAMS; + DHCP_OPT[dhcp_state.opt_ptr++] = 3; + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAM_SUBNET; + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAM_ROUTER; + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAM_DNS; + + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_END; + // Padding to 300 bytes + DHCP_OPT[dhcp_state.opt_ptr++] = 0; + DHCP_OPT[dhcp_state.opt_ptr++] = 0; + DHCP_OPT[dhcp_state.opt_ptr++] = 0; + DHCP_OPT[dhcp_state.opt_ptr++] = 0; + DHCP_OPT[dhcp_state.opt_ptr++] = 0; + DHCP_OPT[dhcp_state.opt_ptr++] = 0; + + uip_udp_send(sizeof(struct dhcp_pkt) + dhcp_state.opt_ptr); + dhcp_state.state = DHCP_DISCOVER_SENT; + dhcp_state.ticks = SYS_TICK_HZ; + dhcp_state.dhcp_timer = 30; // Timeout for discover +} + + +void dhcp_send_request(void) +{ + print_string("dhcp_send_request called\n"); + dhcp_prepare_request(); + + dhcp_state.opt_ptr = 0; + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_MESSAGE_TYPE; + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_MESSAGE_TYPE_LEN; + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_MESSAGE_REQUEST; + + dhcp_addopt_client_id(); + dhcp_addopt_request_ip(); + dhcp_addopt_server_id(); + + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAMS; + DHCP_OPT[dhcp_state.opt_ptr++] = 3; + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAM_SUBNET; + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAM_ROUTER; + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAM_DNS; + + DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_END; + // Padding to 300 bytes + DHCP_OPT[dhcp_state.opt_ptr++] = 0; + DHCP_OPT[dhcp_state.opt_ptr++] = 0; + DHCP_OPT[dhcp_state.opt_ptr++] = 0; + DHCP_OPT[dhcp_state.opt_ptr++] = 0; + DHCP_OPT[dhcp_state.opt_ptr++] = 0; + DHCP_OPT[dhcp_state.opt_ptr++] = 0; + + uip_udp_send(sizeof(struct dhcp_pkt) + dhcp_state.opt_ptr); + dhcp_state.state = DHCP_REQUEST_SENT; + dhcp_state.ticks = SYS_TICK_HZ; + dhcp_state.dhcp_timer = 30; // Timeout for request +} + + +void ip_opt(uint8_t * __xdata ip) +{ + dhcp_state.opt_ptr++; + uint8_t len = DHCP_OPT[dhcp_state.opt_ptr++]; + *ip++ = DHCP_OPT[dhcp_state.opt_ptr++]; + *ip++ = DHCP_OPT[dhcp_state.opt_ptr++]; + *ip++ = DHCP_OPT[dhcp_state.opt_ptr++]; + *ip++ = DHCP_OPT[dhcp_state.opt_ptr++]; + // There may be more than one IP option, such as 2 DNS servers advertised + dhcp_state.opt_ptr += len - 4; +} + + +void long_opt(void) +{ + dhcp_state.opt_ptr++; + dhcp_state.opt_ptr++; + long_value = DHCP_OPT[dhcp_state.opt_ptr++]; + long_value <<= 8; + long_value |= DHCP_OPT[dhcp_state.opt_ptr++]; + long_value <<= 8; + long_value |= DHCP_OPT[dhcp_state.opt_ptr++]; + long_value <<= 8; + long_value |= DHCP_OPT[dhcp_state.opt_ptr++]; +} + + +void parse_opts(void) +{ + while (DHCP_OPT[dhcp_state.opt_ptr] && DHCP_OPT[dhcp_state.opt_ptr] != DHCP_END) { + switch(DHCP_OPT[dhcp_state.opt_ptr]) { + case DHCP_SUBNET_MASK: + ip_opt(&dhcp_state.subnet[0]); + break; + case DHCP_ROUTER: + ip_opt(&dhcp_state.router[0]); + break; + case DHCP_DNS: + ip_opt(&dhcp_state.dns[0]); + break; + case DHCP_SERVER_ID: + ip_opt(&dhcp_state.server[0]); + break; + case DHCP_BROADCAST: + ip_opt(&dhcp_state.broadcast[0]); + break; + case DHCP_LEASE: + long_opt(); + dhcp_state.lease = long_value; + break; + case DHCP_REBIND: + long_opt(); + dhcp_state.rebind = long_value; + break; + case DHCP_RENEWAL: + long_opt(); + dhcp_state.renewal = long_value; + break; + case DHCP_END: + break; + default: + print_string("Unknown DHCP option: "); print_byte(DHCP_OPT[dhcp_state.opt_ptr]); write_char('\n'); + dhcp_state.opt_ptr++; + dhcp_state.opt_ptr += DHCP_OPT[dhcp_state.opt_ptr]; + dhcp_state.opt_ptr++; + } + } +} + + +void parse_dhcp(void) +{ + if (!DHCP_P->tid == HTONS(dhcp_state.transaction_id)) + return; + if (DHCP_P->cookie[0] != 0x63 || DHCP_P->cookie[1] != 0x82 || DHCP_P->cookie[2] != 0x53 || DHCP_P->cookie[3] != 0x63) + return; + + dhcp_state.opt_ptr = 0; + if (DHCP_OPT[dhcp_state.opt_ptr++] != DHCP_MESSAGE_TYPE || DHCP_OPT[dhcp_state.opt_ptr++] != DHCP_MESSAGE_TYPE_LEN) + return; + if (DHCP_OPT[dhcp_state.opt_ptr] == DHCP_MESSAGE_OFFER) { + dhcp_state.opt_ptr++; + dhcp_state.current_ip[0] = DHCP_P->your_ip[0]; + dhcp_state.current_ip[1] = DHCP_P->your_ip[1]; + dhcp_state.current_ip[2] = DHCP_P->your_ip[2]; + dhcp_state.current_ip[3] = DHCP_P->your_ip[3]; + parse_opts(); + print_string("DHCP offer received for IP "); dhcp_print_ip(dhcp_state.current_ip); + write_char('\n'); + dhcp_send_request(); + } else if (DHCP_OPT[dhcp_state.opt_ptr++] == DHCP_MESSAGE_ACK) { + parse_opts(); + print_string("DHCP ACK, our IP is "); dhcp_print_ip(dhcp_state.current_ip); + write_char('\n'); + print_string("DHCP netmask "); dhcp_print_ip(dhcp_state.subnet); + write_char('\n'); + print_string("DHCP gateway "); dhcp_print_ip(dhcp_state.router); + write_char('\n'); + print_string("DHCP lease-time "); + print_long(dhcp_state.lease); + write_char('\n'); + uip_ipaddr(&uip_hostaddr, dhcp_state.current_ip[0], dhcp_state.current_ip[1], dhcp_state.current_ip[2], dhcp_state.current_ip[3]); + uip_ipaddr(&uip_draddr, dhcp_state.router[0], dhcp_state.router[1], dhcp_state.router[2], dhcp_state.router[3]); + uip_ipaddr(&uip_netmask, dhcp_state.subnet[0], dhcp_state.subnet[1], dhcp_state.subnet[2], dhcp_state.subnet[3]); + dhcp_state.state = DHCP_LEASING; + dhcp_state.ticks = SYS_TICK_HZ; + dhcp_state.dhcp_timer = dhcp_state.renewal > 0xffff ? 0xffff : dhcp_state.renewal; + } +} + + +void dhcp_start(void) __banked +{ + uip_ipaddr(server, 255,255,255,255); + dhcp_state.conn = uip_udp_new(&server, HTONS(DHCPC_SERVER_PORT)); + dhcp_state.current_ip[0] = dhcp_state.current_ip[1] = dhcp_state.current_ip[2] = dhcp_state.current_ip[3] = 0; + if(dhcp_state.conn) { + uip_udp_bind(dhcp_state.conn, HTONS(DHCPC_CLIENT_PORT)); + } else { + print_string("dhcp_start failed to set up socket\n"); + return; + } + get_random_32(); + dhcp_state.transaction_id = SFR_DATA_U32; + dhcp_state.state = DHCP_START; + print_string("dhcp_start done\n"); +} + + +void dhcp_stop(void) __banked +{ + print_string("dhcp_stop called\n"); + uip_udp_remove(dhcp_state.conn); + dhcp_state.state = DHCP_OFF; +} + + +void dhcp_callback(void) __banked +{ + if (!dhcp_state.state) + return; + if (uip_closed()) { + print_string("Closed\n"); + return; + } else if (uip_newdata()) { + parse_dhcp(); + } else { + if (dhcp_state.state == DHCP_START) { + dhcp_send_discover(); + } else if (!--dhcp_state.ticks) { +// print_string("Timer: "); print_short(dhcp_state.ticks); write_char(' '); print_short(dhcp_state.dhcp_timer); + dhcp_state.dhcp_timer--; + dhcp_state.ticks = SYS_TICK_HZ; + } + if (!dhcp_state.dhcp_timer) { + switch (dhcp_state.state) { + case DHCP_DISCOVER_SENT: + dhcp_send_discover(); + break; + case DHCP_LEASING: + case DHCP_REQUEST_SENT: + dhcp_send_request(); + break; + default: + print_string("UNKNOWN STATE\n"); + } + } + } + + // By default we do not send anything out + uip_len = 0; +} diff --git a/dhcp.h b/dhcp.h new file mode 100644 index 0000000..fdcc35d --- /dev/null +++ b/dhcp.h @@ -0,0 +1,48 @@ +#ifndef _DHCP_H_ +#define _DHCP_H_ + +#include "uipopt.h" +#include + +#define DHCPC_SERVER_PORT 67 +#define DHCPC_CLIENT_PORT 68 + +#define DHCP_OFF 0 +#define DHCP_START 1 +#define DHCP_DISCOVER_SENT 2 +#define DHCP_REQUEST_SENT 3 +#define DHCP_LEASING 4 + +void dhcp_start(void) __banked; +void dhcp_stop(void) __banked; +// void dhcp_periodic(void) __banked; +void dhcp_callback(void) __banked; + + +struct dhcp_state { + uint8_t state; + uint32_t transaction_id; + uint16_t dhcp_timer; + uint8_t ticks; + uint16_t opt_ptr; + uint8_t current_ip[4]; + uint8_t server[4]; + uint8_t router[4]; + uint8_t subnet[4]; + uint8_t dns[4]; + uint8_t broadcast[4]; + uint32_t lease; + uint32_t rebind; + uint32_t renewal; + + struct uip_udp_conn *conn; +}; + +typedef struct dhcp_state uip_udp_appstate_t; + +/* Finally we define the application function to be called by uIP. */ +#ifndef UIP_UDP_APPCALL +#define UIP_UDP_APPCALL dhcp_callback +#endif /* UIP_APPCALL */ + +#endif diff --git a/httpd/httpd.c b/httpd/httpd.c index 8e6b28c..d4afc29 100644 --- a/httpd/httpd.c +++ b/httpd/httpd.c @@ -11,7 +11,6 @@ // #define DEBUG #include "debug.h" - #define SESSION_ID_LENGTH 12 #define SESSION_TIMEOUT 200 diff --git a/rtl837x_common.h b/rtl837x_common.h index 57c0e6a..b51799a 100644 --- a/rtl837x_common.h +++ b/rtl837x_common.h @@ -5,6 +5,8 @@ #include #include +#define SYS_TICK_HZ 200 + // SCL and SDA pin numbers for SFP cage 0 and SFP cage 1 #define SCL_PIN 3 #define SDA_PIN_0 4 @@ -88,6 +90,7 @@ void print_string(__code char *p); void print_long(__xdata uint32_t a); void print_short(uint16_t a); void print_byte(uint8_t a); +void itoa(uint8_t v); void print_sfr_data(void); void print_phy_data(void); void phy_write_mask(uint16_t phy_mask, uint8_t dev_id, uint16_t reg, uint16_t v); diff --git a/rtl837x_phy.c b/rtl837x_phy.c index 11732b7..ae68ab6 100644 --- a/rtl837x_phy.c +++ b/rtl837x_phy.c @@ -16,8 +16,8 @@ #include "rtl837x_phy.h" #include "phy.h" -#pragma codeseg BANK1 -#pragma constseg BANK1 +#pragma codeseg BANK2 +#pragma constseg BANK2 extern __code uint16_t bit_mask[16]; diff --git a/rtlplayground.c b/rtlplayground.c index 8bc0730..f45f493 100644 --- a/rtlplayground.c +++ b/rtlplayground.c @@ -12,6 +12,7 @@ #include "rtl837x_port.h" #include "rtl837x_stp.h" #include "rtl837x_igmp.h" +#include "dhcp.h" #include "cmd_parser.h" #include "uip/uipopt.h" #include "uip/uip.h" @@ -80,6 +81,7 @@ volatile __xdata uint32_t ticks; volatile __xdata uint8_t sec_counter; volatile __xdata uint16_t sleep_ticks; __xdata uint8_t stp_clock; +extern __xdata struct dhcp_state dhcp_state; #define STP_TICK_DIVIDER 3 @@ -172,6 +174,22 @@ void write_char(char c) } +void itoa(uint8_t v) +{ + uint8_t t = (v / 100); + // when print_zeros is not zero, we know that a non-zero number has printed. + // That have to print all the next numbers. + uint8_t print_zeros = t; + if (print_zeros) + write_char('0' + t); + t = (v / 10) % 10; + print_zeros |= t; + if (print_zeros) + write_char('0' + t); + write_char('0' + (v % 10)); +} + + void print_string(__code char *p) { while (*p) @@ -910,6 +928,10 @@ void handle_rx(void) uip_arp_out(); tcpip_output(); } + } else { +#ifdef RXTXDBG + print_string("Unknown RX on port "); print_byte(rx_headers[3] & 0xf); write_char('\n'); +#endif } } } @@ -927,6 +949,13 @@ void handle_tx(void) tcpip_output(); } } + for(uint8_t i = 0; i < UIP_UDP_CONNS; i++) { + uip_udp_periodic(i); + if(uip_len > 0) { + uip_arp_out(); + tcpip_output(); + } + } } @@ -1739,6 +1768,7 @@ void bootloader(void) { ticks = 0; stp_clock = STP_TICK_DIVIDER; + dhcp_state.state = DHCP_OFF; sbuf_ptr = 0; CKCON = 0; // Initial Clock configuration diff --git a/tools/Makefile b/tools/Makefile index cca21a7..3533faa 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -2,7 +2,8 @@ CC = gcc CCFLAGS = -Wall -o BUILDDIR = output/ -all: create_build_dir $(BUILDDIR)injector $(BUILDDIR)fileadder $(BUILDDIR)httpd_sim $(BUILDDIR)crc_calculator +all: create_build_dir $(BUILDDIR)injector $(BUILDDIR)fileadder $(BUILDDIR)httpd_sim\ + $(BUILDDIR)crc_calculator $(BUILDDIR)imagebuilder create_build_dir: mkdir -p $(BUILDDIR) @@ -21,3 +22,6 @@ $(BUILDDIR)crc_calculator: crc_calculator.c $(BUILDDIR)httpd_sim: httpd_sim.c httpd_sim.h gcc $< $(CCFLAGS) $@ -I/usr/include/json-c -ljson-c + +$(BUILDDIR)imagebuilder: imagebuilder.c + gcc $^ $(CCFLAGS) $@ diff --git a/tools/imagebuilder.c b/tools/imagebuilder.c new file mode 100644 index 0000000..a965d0d --- /dev/null +++ b/tools/imagebuilder.c @@ -0,0 +1,166 @@ +/* + * Adds data files into specified locations of an image, optionally creates + * an index in the form of a header file + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define OFFSET 2 +#define BANK0_SIZE 0x4000 +#define BANK_SIZE 0xc000 +#define BANK_STRIDE 0x10000 + +// Use a 4MB buffer, the maximum flash rom size +#define BUFFER_SIZE 0x400000 +uint8_t buffer[BUFFER_SIZE]; +FILE *inptr; +int outptr; + +const char *argp_program_version = "imagebuilder 0.1"; +const char *argp_program_bug_address = ""; +static char doc[] = "Create an image with multiple banks for RTL837X-based switches"; +static char args_doc[] = "INPUT_IMAGE"; +static struct argp_option options[] = { + { "input", 'i', "FILE", 0, "Input file"}, + { 0 } +}; + + +struct arguments { + char *input_file; +}; + + +static error_t parse_opt(int key, char *arg, struct argp_state *state) +{ + struct arguments *arguments = state->input; + switch (key) { + case 'i': + arguments->input_file = arg; + break; + case ARGP_KEY_END: + if (state->arg_num < 1) // Expect 1 command line argument at end + argp_usage(state); + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + + +static struct argp argp = { + options, parse_opt, args_doc, doc, 0, 0, 0 +}; + + +int main(int argc, char **argv) +{ + struct arguments arguments; + int arg_index; + + arguments.input_file = NULL; + + argp_parse(&argp, argc, argv, 0, &arg_index, &arguments); + + memset(buffer, 0, BUFFER_SIZE); + + size_t filesize = 0; + inptr = fopen(arguments.input_file, "rb"); + if (inptr == NULL) { + printf("Cannot open input file %s\n", arguments.input_file); + return 5; + } + + fseek(inptr, 0L, SEEK_END); + filesize = ftell(inptr); + rewind(inptr); + printf("Input file size: %ld\n", filesize); + if (filesize > BUFFER_SIZE) { + printf("File too large.\n"); + return 5; + } + + int nbanks = (filesize - BANK0_SIZE) / BANK_STRIDE; + printf("Input file contains %d banks\n", nbanks); + + /* Verify the size of banks in input file: + * Bank 0: 0x00002 - 0x04000 <- 0x00000 - 0x03ffe + * Bank 1: 0x04000 - 0x10000 <- 0x14000 - 0x20000 + * Bank 2: 0x10000 - 0x1c000 <- 0x24000 - 0x33000 + * [...] + * by verifying whether other than 0-bytes are found in the input + * file after these ranges. + */ + size_t bytes_read = fread(buffer, 1, filesize, inptr); + if (bytes_read != filesize) { + printf("Error reading input file.\n"); + return 5; + } + for (int b = BANK0_SIZE; b < BANK_STRIDE + BANK0_SIZE; b ++) { + if (buffer[b]) { + printf("WARNING: Bank 0: code segment too large at 0x%x!\n", b); + break; + } + } + for (int bank = 1; bank <= nbanks; bank++) { + for (int b = (bank + 1) * BANK_STRIDE; b < (bank + 1) * BANK_STRIDE + BANK0_SIZE; b ++) { + if (buffer[b]) { + printf("WARNING: Bank %d: code segment too large at 0x%x!\n", bank, b); + break; + } + } + } + + rewind(inptr); + memset(buffer, 0, BUFFER_SIZE); + + // BANK0-Size + buffer[0] = 0x00; + buffer[1] = 0x40; + + // Read bank 0 + bytes_read = fread(buffer + OFFSET, 1, BANK0_SIZE, inptr); + printf("Bank 0: Bytes read: %ld\n", bytes_read); + + if (bytes_read != BANK0_SIZE) { + printf("Error reading input file.\n"); + return 5; + } + fseek(inptr, BANK_STRIDE, SEEK_CUR); + + for (int bank = 1; bank <= nbanks; bank++) { + bytes_read = fread(buffer + (bank - 1) * BANK_SIZE + BANK0_SIZE, 1, BANK_SIZE, inptr); + printf("Bank %d: bytes read: %ld\n", bank, bytes_read); + if (bank != nbanks) + fseek(inptr, BANK0_SIZE, SEEK_CUR); + } + + fclose(inptr); + + outptr = creat(argv[arg_index], S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + + if (!outptr) { + printf("Cannot open %s\n", argv[arg_index]); + return 5; + } + + size_t written = write(outptr, buffer, (nbanks + 1) * BANK_STRIDE); + + if (written != (nbanks + 1) * BANK_STRIDE) { + printf("Error writing output file.\n"); + return 5; + } + close(outptr); + + return 0; +} diff --git a/uip/uip-conf.h b/uip/uip-conf.h index 08f7439..a413c83 100644 --- a/uip/uip-conf.h +++ b/uip/uip-conf.h @@ -129,14 +129,18 @@ typedef unsigned short uip_stats_t; * * \hideinitializer */ -#define UIP_CONF_UDP 0 +#define UIP_CONF_UDP 1 /** * UDP checksums on or off + * The RTL8372/3 are able to calculate and verify all L2 and L3 checksums + * in hardware. The TX checksums are configured in the CPU-tag of outgoing + * packets, while the RTL837X_NIC_RX_CTRL register configures the verification + * of the checksum of inbound packets and subsequent possible drop. * * \hideinitializer */ -#define UIP_CONF_UDP_CHECKSUMS 1 +#define UIP_CONF_UDP_CHECKSUMS 0 /** * uIP statistics on or off @@ -149,6 +153,7 @@ typedef unsigned short uip_stats_t; our project. */ /*#include "smtp.h"*/ #include "httpd.h" +#include "dhcp.h" /*#include "telnetd.h"*/ /*#include "webserver.h" */ /*#include "dhcpc.h"*/ diff --git a/uip/uip.c b/uip/uip.c index 910191a..f2d6767 100644 --- a/uip/uip.c +++ b/uip/uip.c @@ -85,6 +85,7 @@ #include "uip.h" #include "uipopt.h" #include "uip_arch.h" +#include #pragma codeseg BANK1 #pragma constseg BANK1 @@ -168,8 +169,8 @@ __xdata u16_t uip_listenports[UIP_LISTENPORTS]; /* The uip_listenports list all currently listning ports. */ #if UIP_UDP -struct uip_udp_conn *uip_udp_conn; -struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS]; +__xdata struct uip_udp_conn *uip_udp_conn; +__xdata struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS]; #endif /* UIP_UDP */ __xdata static u16_t ipid; /* Ths ipid variable is an increasing @@ -401,7 +402,7 @@ uip_init(void) __banked /*---------------------------------------------------------------------------*/ #if UIP_ACTIVE_OPEN __xdata struct uip_conn * -uip_connect(register __xdata uip_ipaddr_t *ripaddr, __xdata u16_t rport) +uip_connect(register __xdata uip_ipaddr_t *ripaddr, __xdata u16_t rport) __banked { __xdata struct uip_conn *conn, *cconn; @@ -467,9 +468,9 @@ uip_connect(register __xdata uip_ipaddr_t *ripaddr, __xdata u16_t rport) /*---------------------------------------------------------------------------*/ #if UIP_UDP struct uip_udp_conn * -uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport) +uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport) __banked { - register struct uip_udp_conn *conn; + __xdata struct uip_udp_conn *conn; /* Find an unused local port. */ again: @@ -512,7 +513,7 @@ uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport) #endif /* UIP_UDP */ /*---------------------------------------------------------------------------*/ void -uip_unlisten(u16_t port) +uip_unlisten(u16_t port) __banked { for(c = 0; c < UIP_LISTENPORTS; ++c) { if(uip_listenports[c] == port) { @@ -523,7 +524,7 @@ uip_unlisten(u16_t port) } /*---------------------------------------------------------------------------*/ void -uip_listen(u16_t port) +uip_listen(u16_t port) __banked { for(c = 0; c < UIP_LISTENPORTS; ++c) { if(uip_listenports[c] == 0) { @@ -721,7 +722,6 @@ uip_process(u8_t flag) __banked /* Reset the length variables. */ uip_len = 0; uip_slen = 0; - /* Check if the connection is in a state in which we simply wait for the connection to time out. If so, we increase the connection's timer and remove the connection if it times @@ -919,12 +919,14 @@ uip_process(u8_t flag) __banked } #endif /* UIP_BROADCAST */ - /* Check if the packet is destined for our IP address. */ + /* Check if we have a DHCP packet, otherwise check if the packet is destined for our IP address. */ #if !UIP_CONF_IPV6 - if(!uip_ipaddr_cmpx(BUF->destipaddr, uip_hostaddr)) { - UIP_STAT(++uip_stat.ip.drop); - goto drop; - } + if(!(BUF->proto == UIP_PROTO_UDP && UDPBUF->destport == HTONS(DHCPC_CLIENT_PORT))) { + if(!uip_ipaddr_cmpx(BUF->destipaddr, uip_hostaddr)) { + UIP_STAT(++uip_stat.ip.drop); + goto drop; + } + } #else /* UIP_CONF_IPV6 */ /* For IPv6, packet reception is a little trickier as we need to make sure that we listen to certain multicast addresses (all @@ -1901,7 +1903,7 @@ htons(u16_t val) } /*---------------------------------------------------------------------------*/ void -uip_send(register __xdata const void *data, register uint16_t len) +uip_send(register __xdata const void *data, register uint16_t len) __banked { if(len > 0) { uip_slen = len; diff --git a/uip/uip.h b/uip/uip.h index 35933aa..2433512 100644 --- a/uip/uip.h +++ b/uip/uip.h @@ -447,7 +447,7 @@ void uip_setipid(u16_t id); * * \param port A 16-bit port number in network byte order. */ -void uip_listen(u16_t port); +void uip_listen(u16_t port) __banked; /** * Stop listening to the specified port. @@ -461,7 +461,7 @@ void uip_listen(u16_t port); * * \param port A 16-bit port number in network byte order. */ -void uip_unlisten(u16_t port); +void uip_unlisten(u16_t port) __banked; /** * Connect to a remote host using TCP. @@ -495,7 +495,7 @@ void uip_unlisten(u16_t port); * or NULL if no connection could be allocated. * */ -__xdata struct uip_conn *uip_connect(register __xdata uip_ipaddr_t *ripaddr, __xdata u16_t port); +__xdata struct uip_conn *uip_connect(register __xdata uip_ipaddr_t *ripaddr, __xdata u16_t port) __banked; @@ -535,7 +535,7 @@ __xdata struct uip_conn *uip_connect(register __xdata uip_ipaddr_t *ripaddr, __x * * \hideinitializer */ -void uip_send(register __xdata const void *data, register uint16_t len); +void uip_send(register __xdata const void *data, register uint16_t len) __banked; /** * The length of any incoming data that is currently avaliable (if avaliable) @@ -763,7 +763,7 @@ void uip_send(register __xdata const void *data, register uint16_t len); * \return The uip_udp_conn structure for the new connection or NULL * if no connection could be allocated. */ -struct uip_udp_conn *uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport); +struct uip_udp_conn *uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport) __banked; /** * Removed a UDP connection. @@ -1224,8 +1224,8 @@ struct uip_udp_conn { /** * The current UDP connection. */ -extern struct uip_udp_conn *uip_udp_conn; -extern struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS]; +extern __xdata struct uip_udp_conn *uip_udp_conn; +extern __xdata struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS]; #endif /* UIP_UDP */ /** @@ -1538,58 +1538,6 @@ extern __xdata uip_ipaddr_t uip_hostaddr, uip_netmask, uip_draddr; extern __xdata uip_ipaddr_t uip_hostaddr, uip_netmask, uip_draddr; #endif /* UIP_FIXEDADDR */ -/** - * Calculate the Internet checksum over a buffer. - * - * The Internet checksum is the one's complement of the one's - * complement sum of all 16-bit words in the buffer. - * - * See RFC1071. - * - * \param buf A pointer to the buffer over which the checksum is to be - * computed. - * - * \param len The length of the buffer over which the checksum is to - * be computed. - * - * \return The Internet checksum of the buffer. - */ -u16_t uip_chksum(u16_t *buf, u16_t len); - -/** - * Calculate the IP header checksum of the packet header in uip_buf. - * - * The IP header checksum is the Internet checksum of the 20 bytes of - * the IP header. - * - * \return The IP header checksum of the IP header in the uip_buf - * buffer. - */ -u16_t uip_ipchksum(void); - -/** - * Calculate the TCP checksum of the packet in uip_buf and uip_appdata. - * - * The TCP checksum is the Internet checksum of data contents of the - * TCP segment, and a pseudo-header as defined in RFC793. - * - * \return The TCP checksum of the TCP segment in uip_buf and pointed - * to by uip_appdata. - */ -u16_t uip_tcpchksum(void); - -/** - * Calculate the UDP checksum of the packet in uip_buf and uip_appdata. - * - * The UDP checksum is the Internet checksum of data contents of the - * UDP segment, and a pseudo-header as defined in RFC768. - * - * \return The UDP checksum of the UDP segment in uip_buf and pointed - * to by uip_appdata. - */ -u16_t uip_udpchksum(void); - - #endif /* __UIP_H__ */