From c5e62b72053fb56a4501e4b36d1df9831dbbcfa6 Mon Sep 17 00:00:00 2001 From: ksb Date: Sat, 11 Jul 2009 14:37:11 +0000 Subject: [PATCH] USB CDC-Ethernet class --- .../common/usb/cdc-eth/cdc-eth-descriptors.c | 122 +++++ .../usb/cdc-eth/cdc-eth-string-descriptors.c | 43 ++ cpu/arm/common/usb/cdc-eth/cdc-eth.c | 170 +++++++ cpu/arm/common/usb/cdc-eth/cdc-eth.h | 13 + cpu/arm/common/usb/cdc-eth/dhcps.c | 451 ++++++++++++++++++ cpu/arm/common/usb/cdc-eth/dhcps.h | 47 ++ 6 files changed, 846 insertions(+) create mode 100644 cpu/arm/common/usb/cdc-eth/cdc-eth-descriptors.c create mode 100644 cpu/arm/common/usb/cdc-eth/cdc-eth-string-descriptors.c create mode 100644 cpu/arm/common/usb/cdc-eth/cdc-eth.c create mode 100644 cpu/arm/common/usb/cdc-eth/cdc-eth.h create mode 100644 cpu/arm/common/usb/cdc-eth/dhcps.c create mode 100644 cpu/arm/common/usb/cdc-eth/dhcps.h diff --git a/cpu/arm/common/usb/cdc-eth/cdc-eth-descriptors.c b/cpu/arm/common/usb/cdc-eth/cdc-eth-descriptors.c new file mode 100644 index 000000000..bc243005a --- /dev/null +++ b/cpu/arm/common/usb/cdc-eth/cdc-eth-descriptors.c @@ -0,0 +1,122 @@ +#include "descriptors.h" +#include +#include +#include + +const struct usb_st_device_descriptor device_descriptor = + { + sizeof(struct usb_st_device_descriptor), + DEVICE, + 0x0210, + CDC, + 0, + 0, + CTRL_EP_SIZE, + 0xffff, + 0xffff, + 0x0010, + 2, + 1, + 3, + 1 + }; + +const struct configuration_st { + struct usb_st_configuration_descriptor configuration; + struct usb_st_interface_descriptor comm; + struct usb_cdc_header_func_descriptor header; + struct usb_cdc_union_func_descriptor union_descr; + struct usb_cdc_ethernet_func_descriptor ethernet; +#if 1 + struct usb_st_endpoint_descriptor ep_notification; +#endif + struct usb_st_interface_descriptor data; + struct usb_st_endpoint_descriptor ep_in; + struct usb_st_endpoint_descriptor ep_out; +} BYTE_ALIGNED configuration_block = + { + /* Configuration */ + { + sizeof(configuration_block.configuration), + CONFIGURATION, + sizeof(configuration_block), + 2, + 1, + 0, + 0x80, + 50 + }, + { + sizeof(configuration_block.comm), + INTERFACE, + 0, + 0, + 1, + CDC, + ETHERNET_NETWORKING_CONTROL_MODEL, + 0, + 0 + }, + { + sizeof(configuration_block.header), + CS_INTERFACE, + CDC_FUNC_DESCR_HEADER, + 0x0110 + }, + { + sizeof(configuration_block.union_descr), + CS_INTERFACE, + CDC_FUNC_DESCR_UNION, + 0, /* Master */ + {1} /* Slave */ + }, + { + sizeof(configuration_block.ethernet), + CS_INTERFACE, + CDC_FUNC_DESCR_ETHERNET, + 4, + 0, /* No statistics */ + UIP_CONF_BUFFER_SIZE - UIP_CONF_LLH_LEN + 14, + 0, /* No multicast filters */ + 0 /* No wake-up filters */ + }, + { + sizeof(configuration_block.ep_notification), + ENDPOINT, + 0x83, + 0x03, + 8, + 100 + }, + { + sizeof(configuration_block.data), + INTERFACE, + 1, + 0, + 2, + CDC_DATA, + 0, + TRANSPARENT_PROTOCOL, + 0 + }, + { + sizeof(configuration_block.ep_in), + ENDPOINT, + 0x81, + 0x02, + 64, + 0 + }, + { + sizeof(configuration_block.ep_out), + ENDPOINT, + 0x02, + 0x02, + 64, + 0 + } + + }; + +const struct usb_st_configuration_descriptor const *configuration_head = +(struct usb_st_configuration_descriptor const*)&configuration_block; diff --git a/cpu/arm/common/usb/cdc-eth/cdc-eth-string-descriptors.c b/cpu/arm/common/usb/cdc-eth/cdc-eth-string-descriptors.c new file mode 100644 index 000000000..72d1d4d1a --- /dev/null +++ b/cpu/arm/common/usb/cdc-eth/cdc-eth-string-descriptors.c @@ -0,0 +1,43 @@ +#include "string-descriptors.h" +static const struct { + struct usb_st_string_descriptor base; + Uint16 chars[18]; +} string_descriptor_1_en= {{40, 3, {'U'}}, { +'S', 'B', ' ', 'p', 's', 'e', 'u', 'd', 'o', ' ', 'e', 't', 'h', 'e', 'r', 'n', 'e', 't'}}; +static const struct { + struct usb_st_string_descriptor base; + Uint16 chars[8]; +} string_descriptor_2_all= {{20, 3, {'F'}}, { +'l', 'u', 'f', 'f', 'w', 'a', 'r', 'e'}}; +static const struct { + struct usb_st_string_descriptor base; + Uint16 chars[2]; +} string_descriptor_3_all= {{8, 3, {'0'}}, { +'.', '1'}}; +static const struct { + struct usb_st_string_descriptor base; + Uint16 chars[11]; +} string_descriptor_4_all= {{26, 3, {'0'}}, { +'2', '0', '0', '0', '0', '0', '0', '0', '0', '0', '1'}}; +static const struct usb_st_string_descriptor * string_table_en[] = +{ + &string_descriptor_1_en.base, + &string_descriptor_2_all.base, + &string_descriptor_3_all.base, + &string_descriptor_4_all.base, +}; +static const struct { + struct usb_st_language_descriptor base; + Uint16 langs[0]; +} language_descriptor = +{ + {4, 3, {0x0409}}, + {}}; +static const struct { + struct usb_st_string_languages base; + struct usb_st_string_language_map map[0]; +} string_languages_full={{1, 4, &language_descriptor.base, + {{0x0409, string_table_en}}}, { + } +}; +const struct usb_st_string_languages * const string_languages = &string_languages_full.base; diff --git a/cpu/arm/common/usb/cdc-eth/cdc-eth.c b/cpu/arm/common/usb/cdc-eth/cdc-eth.c new file mode 100644 index 000000000..1e85872fd --- /dev/null +++ b/cpu/arm/common/usb/cdc-eth/cdc-eth.c @@ -0,0 +1,170 @@ +#include +#include +#include +#include +#include +#include + +#define DATA_IN 0x81 +#define DATA_OUT 0x02 +#define INTERRUPT_IN 0x83 + + +struct uip_eth_addr default_uip_ethaddr = {{0x02,0x00,0x00,0x00,0x00,0x02}}; + +static unsigned int +handle_cdc_eth_requests() +{ + return 0; +} + +static const struct USBRequestHandler cdc_eth_request_handler = + { + 0x21, 0x7f, + 0x00, 0x00, + handle_cdc_eth_requests + }; + +static struct USBRequestHandlerHook cdc_eth_request_hook = + { + NULL, + &cdc_eth_request_handler + }; + +static USBBuffer recv_buffer; +static uint8_t recv_data[UIP_BUFSIZE]; + +static USBBuffer xmit_buffer[3]; +static uint8_t xmit_data[UIP_BUFSIZE]; + +static void +init_recv_buffer() +{ + recv_buffer.next = NULL; + recv_buffer.data = recv_data; + recv_buffer.left = UIP_BUFSIZE; + recv_buffer.flags = USB_BUFFER_SHORT_END | USB_BUFFER_NOTIFY; +} + +u8_t +usbeth_send(void) +{ + if ((xmit_buffer[0].flags & USB_BUFFER_SUBMITTED)) return UIP_FW_DROPPED; + uip_arp_out(); + memcpy(xmit_data, uip_buf, uip_len); + xmit_buffer[0].next = NULL; + xmit_buffer[0].left = uip_len; + xmit_buffer[0].flags = USB_BUFFER_NOTIFY | USB_BUFFER_SHORT_END; + xmit_buffer[0].data = xmit_data; + + /* printf("usbeth_send: %d\n", uip_len); */ + usb_submit_xmit_buffer(DATA_IN, &xmit_buffer[0]); + return UIP_FW_OK; +} + +static struct uip_fw_netif usbethif = + {UIP_FW_NETIF(172,16,0,1, 255,255,255,255, usbeth_send)}; + +#define BUF ((struct uip_eth_hdr *)&uip_buf[0]) + +PROCESS(usb_eth_process, "USB ethernet"); + +PROCESS_THREAD(usb_eth_process, ev , data) +{ + PROCESS_BEGIN(); + usb_register_request_handler(&cdc_eth_request_hook); + usb_setup(); + usb_set_ep_event_process(DATA_OUT, process_current); + usb_set_global_event_process(process_current); + uip_fw_default(&usbethif); + uip_setethaddr(default_uip_ethaddr); + uip_arp_init(); + + while(1) { + PROCESS_WAIT_EVENT(); + if (ev == PROCESS_EVENT_EXIT) break; + if (ev == PROCESS_EVENT_POLL) { + unsigned int events = usb_get_global_events(); + if (events) { + if (events & USB_EVENT_CONFIG) { + if (usb_get_current_configuration() != 0) { + printf("Configured\n"); + usb_setup_bulk_endpoint(DATA_IN); + usb_setup_bulk_endpoint(DATA_OUT); + usb_setup_interrupt_endpoint(INTERRUPT_IN); + init_recv_buffer(); + usb_submit_recv_buffer(DATA_OUT, &recv_buffer); +#if 0 + { + static const uint8_t foo[4] = {0x12,0x34,0x56,0x78}; + xmit_buffer[0].next = NULL; + xmit_buffer[0].left = sizeof(foo); + xmit_buffer[0].flags = USB_BUFFER_SHORT_END; + xmit_buffer[0].data = &foo; + + usb_submit_xmit_buffer(DATA_IN, &xmit_buffer[0]); + } +#endif + } else { + usb_disable_endpoint(DATA_IN); + usb_disable_endpoint(DATA_OUT); + usb_disable_endpoint(INTERRUPT_IN); + } + } + } + events = usb_get_ep_events(DATA_OUT); + if (events & USB_EP_EVENT_NOTIFICATION) { + uip_len = sizeof(recv_data) - recv_buffer.left; + /* printf("Received: %d bytes\n", uip_len); */ + memcpy(uip_buf, recv_data, uip_len); +#if UIP_CONF_IPV6 + if(BUF->type == htons(UIP_ETHTYPE_IPV6)) { + uip_neighbor_add(&IPBUF->srcipaddr, &BUF->src); + tcpip_input(); + } else +#endif /* UIP_CONF_IPV6 */ + if(BUF->type == htons(UIP_ETHTYPE_IP)) { + uip_len -= sizeof(struct uip_eth_hdr); + tcpip_input(); + } else if(BUF->type == htons(UIP_ETHTYPE_ARP)) { + uip_arp_arpin(); + /* If the above function invocation resulted in data that + should be sent out on the network, the global variable + uip_len is set to a value > 0. */ + if (uip_len > 0) { + memcpy(xmit_data, uip_buf, uip_len); + xmit_buffer[0].next = NULL; + xmit_buffer[0].data = xmit_data; + xmit_buffer[0].left = uip_len; + xmit_buffer[0].flags = USB_BUFFER_SHORT_END; + + usb_submit_xmit_buffer(DATA_IN, &xmit_buffer[0]); + /* printf("Sent: %d bytes\n", uip_len); */ + } + } + + init_recv_buffer(); + usb_submit_recv_buffer(DATA_OUT, &recv_buffer); + } + } + } + PROCESS_END(); +} + +void +usb_cdc_eth_setup() +{ + process_start(&usb_eth_process, NULL); +} + +void +usb_cdc_eth_set_ifaddr(uip_ipaddr_t *addr) +{ + usbethif.ipaddr = *addr; +} + +void +dummy(uip_ipaddr_t *addr1, uip_ipaddr_t *addr2) +{ + *addr1 = *addr2; +} diff --git a/cpu/arm/common/usb/cdc-eth/cdc-eth.h b/cpu/arm/common/usb/cdc-eth/cdc-eth.h new file mode 100644 index 000000000..bfdb4202a --- /dev/null +++ b/cpu/arm/common/usb/cdc-eth/cdc-eth.h @@ -0,0 +1,13 @@ +#ifndef __CDC_ETH_H__NUI0ULFC7C__ +#define __CDC_ETH_H__NUI0ULFC7C__ + +#include + +/* Should be called before usb_cdc_eth_setup */ +void +usb_cdc_eth_set_ifaddr(uip_ipaddr_t *addr); + +void +usb_cdc_eth_setup(); + +#endif /* __CDC_ETH_H__NUI0ULFC7C__ */ diff --git a/cpu/arm/common/usb/cdc-eth/dhcps.c b/cpu/arm/common/usb/cdc-eth/dhcps.c new file mode 100644 index 000000000..f994d0b12 --- /dev/null +++ b/cpu/arm/common/usb/cdc-eth/dhcps.c @@ -0,0 +1,451 @@ +/* Adapted by Simon Berg from net/dhcpc.c */ +/* + * Copyright (c) 2005, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * @(#)$Id: dhcps.c,v 1.1 2009/07/11 14:37:11 ksb Exp $ + */ + +#include +#include +#include +#include "contiki.h" +#include "contiki-net.h" +#include "dhcps.h" + +struct dhcp_msg { + uint8_t op, htype, hlen, hops; + uint8_t xid[4]; + uint16_t secs, flags; + uint8_t ciaddr[4]; + uint8_t yiaddr[4]; + uint8_t siaddr[4]; + uint8_t giaddr[4]; + uint8_t chaddr[16]; +#ifndef UIP_CONF_DHCP_LIGHT + uint8_t sname[64]; + uint8_t file[128]; +#endif + uint8_t options[312]; +} CC_BYTE_ALIGNED; + +#define BOOTP_BROADCAST 0x8000 + +#define DHCP_REQUEST 1 +#define DHCP_REPLY 2 +#define DHCP_HTYPE_ETHERNET 1 +#define DHCP_HLEN_ETHERNET 6 +#define DHCP_MSG_LEN 236 + +#define DHCPS_SERVER_PORT 67 +#define DHCPS_CLIENT_PORT 68 + +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 +#define DHCPINFORM 8 + +#define DHCP_OPTION_SUBNET_MASK 1 +#define DHCP_OPTION_ROUTER 3 +#define DHCP_OPTION_DNS_SERVER 6 +#define DHCP_OPTION_REQ_IPADDR 50 +#define DHCP_OPTION_LEASE_TIME 51 +#define DHCP_OPTION_MSG_TYPE 53 +#define DHCP_OPTION_SERVER_ID 54 +#define DHCP_OPTION_REQ_LIST 55 +#define DHCP_OPTION_END 255 + + + +#define LEASE_FLAGS_ALLOCATED 0x01 /* Lease with an allocated address*/ +#define LEASE_FLAGS_VALID 0x02 /* Contains a valid but + possibly outdated lease */ + + +static const struct dhcps_config *config; + + +static uint8_t * +find_option(uint8_t option) +{ + struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; + uint8_t *optptr = &m->options[4]; + uint8_t *end = (uint8_t*)uip_appdata + uip_datalen(); + while(optptr < end && *optptr != DHCP_OPTION_END) { + if(*optptr == option) { + return optptr; + } + optptr += optptr[1] + 2; + } + return NULL; +} + +static const uint8_t magic_cookie[4] = {99, 130, 83, 99}; + +static int +check_cookie(void) +{ + struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; + return memcmp(m->options, magic_cookie, 4) == 0; +} + +/* Finds any valid lease for a given MAC address */ +static struct dhcps_client_lease * +lookup_lease_mac(const uint8_t *chaddr, uint8_t hlen) +{ + struct dhcps_client_lease *lease = config->leases; + struct dhcps_client_lease *end = config->leases + config->num_leases; + while(lease != end) { + if (lease->flags & LEASE_FLAGS_VALID + && memcmp(lease->chaddr, chaddr, hlen) == 0) { + return lease; + } + lease++; + } + return NULL; +} + +static struct dhcps_client_lease * +lookup_lease_ip(const uip_ipaddr_t *ip) +{ + struct dhcps_client_lease *lease = config->leases; + struct dhcps_client_lease *end = config->leases + config->num_leases; + while(lease != end) { + if (uip_ipaddr_cmp(&lease->ipaddr, ip)) { + return lease; + } + lease++; + } + return NULL; +} + +static struct dhcps_client_lease * +find_free_lease(void) +{ + struct dhcps_client_lease *found = NULL; + struct dhcps_client_lease *lease = config->leases; + struct dhcps_client_lease *end = config->leases + config->num_leases; + while(lease != end) { + if (!(lease->flags & LEASE_FLAGS_VALID)) return lease; + if (!(lease->flags & LEASE_FLAGS_ALLOCATED)) found = lease; + lease++; + } + return found; +} + +struct dhcps_client_lease * +init_lease(struct dhcps_client_lease *lease, + const uint8_t *chaddr, uint8_t hlen) +{ + if (lease) { + memcpy(lease->chaddr, chaddr, hlen); + lease->flags = LEASE_FLAGS_VALID; + } + return lease; +} + + +static struct dhcps_client_lease * +choose_address() +{ + struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; + struct dhcps_client_lease *lease; + lease = lookup_lease_mac(m->chaddr, m->hlen); + if (lease) { + return lease; + } + { + uint8_t *opt; + opt = find_option(DHCP_OPTION_REQ_IPADDR); + if (opt && (lease = lookup_lease_ip((uip_ipaddr_t*)&opt[2])) + && !(lease->flags & LEASE_FLAGS_ALLOCATED)) { + return init_lease(lease, m->chaddr,m->hlen); + } + } + lease = find_free_lease(); + if (lease) { + return init_lease(lease, m->chaddr,m->hlen); + } + return NULL; +} + +static struct dhcps_client_lease * +allocate_address() +{ + struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; + struct dhcps_client_lease *lease; + lease = lookup_lease_mac(m->chaddr, m->hlen); + if (!lease) { + uint8_t *opt; + opt = find_option(DHCP_OPTION_REQ_IPADDR); + if (!(opt && (lease = lookup_lease_ip((uip_ipaddr_t*)&opt[2])) + && !(lease->flags & LEASE_FLAGS_ALLOCATED))) { + return NULL; + } + } + lease->lease_end = clock_seconds()+config->default_lease_time; + lease->flags |= LEASE_FLAGS_ALLOCATED; + return lease; +} + +static struct dhcps_client_lease * +release_address() +{ + struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; + struct dhcps_client_lease *lease; + lease = lookup_lease_mac(m->chaddr, m->hlen); + if (!lease) { + return NULL; + } + lease->flags &= ~LEASE_FLAGS_ALLOCATED; + return lease; +} + +/*---------------------------------------------------------------------------*/ +static uint8_t * +add_msg_type(uint8_t *optptr, uint8_t type) +{ + *optptr++ = DHCP_OPTION_MSG_TYPE; + *optptr++ = 1; + *optptr++ = type; + return optptr; +} +/*---------------------------------------------------------------------------*/ +static uint8_t * +add_server_id(uint8_t *optptr) +{ + *optptr++ = DHCP_OPTION_SERVER_ID; + *optptr++ = 4; + memcpy(optptr, &uip_hostaddr, 4); + return optptr + 4; +} +/*---------------------------------------------------------------------------*/ +static uint8_t * +add_lease_time(uint8_t *optptr) +{ + uint32_t lt; + *optptr++ = DHCP_OPTION_LEASE_TIME; + *optptr++ = 4; + lt = HTONL(config->default_lease_time); + memcpy(optptr, <, 4); + return optptr + 4; +} + +/*---------------------------------------------------------------------------*/ +static uint8_t * +add_end(uint8_t *optptr) +{ + *optptr++ = DHCP_OPTION_END; + return optptr; +} + +static uint8_t * +add_config(uint8_t *optptr) +{ + if (config->flags & DHCP_CONF_NETMASK) { + *optptr++ = DHCP_OPTION_SUBNET_MASK; + *optptr++ = 4; + memcpy(optptr, &config->netmask, 4); + optptr += 4; + } + if (config->flags & DHCP_CONF_DNSADDR) { + *optptr++ = DHCP_OPTION_DNS_SERVER; + *optptr++ = 4; + memcpy(optptr, &config->dnsaddr, 4); + optptr += 4; + } + if (config->flags & DHCP_CONF_DEFAULT_ROUTER) { + *optptr++ = DHCP_OPTION_ROUTER; + *optptr++ = 4; + memcpy(optptr, &config->default_router, 4); + optptr += 4; + } + return optptr; +} + +static void +create_msg(CC_REGISTER_ARG struct dhcp_msg *m) +{ + m->op = DHCP_REPLY; + /* m->htype = DHCP_HTYPE_ETHERNET; */ +/* m->hlen = DHCP_HLEN_ETHERNET; */ +/* memcpy(m->chaddr, &uip_ethaddr,DHCP_HLEN_ETHERNET); */ + m->hops = 0; + m->secs = 0; + memcpy(m->siaddr, &uip_hostaddr, 4); + m->sname[0] = '\0'; + m->file[0] = '\0'; + memcpy(m->options, magic_cookie, sizeof(magic_cookie)); +} + +static uip_ipaddr_t any_addr; +static uip_ipaddr_t bcast_addr; + +/*---------------------------------------------------------------------------*/ +static void +send_offer(struct uip_udp_conn *conn, struct dhcps_client_lease *lease) +{ + u8_t *end; + struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; + + create_msg(m); + memcpy(&m->yiaddr, &lease->ipaddr,4); + + end = add_msg_type(&m->options[4], DHCPOFFER); + end = add_server_id(end); + end = add_lease_time(end); + end = add_config(end); + end = add_end(end); + uip_ipaddr_copy(&conn->ripaddr, &bcast_addr); + uip_send(uip_appdata, (int)(end - (u8_t *)uip_appdata)); +} + +static void +send_ack(struct uip_udp_conn *conn, struct dhcps_client_lease *lease) +{ + u8_t *end; + uip_ipaddr_t ciaddr; + struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; + + create_msg(m); + memcpy(&m->yiaddr, &lease->ipaddr,4); + + end = add_msg_type(&m->options[4], DHCPACK); + end = add_server_id(end); + end = add_lease_time(end); + end = add_config(end); + end = add_end(end); + memcpy(&ciaddr, &lease->ipaddr,4); + uip_ipaddr_copy(&conn->ripaddr, &bcast_addr); + uip_send(uip_appdata, (int)(end - (u8_t *)uip_appdata)); + printf("ACK\n"); +} +static void +send_nack(struct uip_udp_conn *conn) +{ + u8_t *end; + struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; + + create_msg(m); + memset(&m->yiaddr, 0, 4); + + end = add_msg_type(&m->options[4], DHCPNAK); + end = add_server_id(end); + end = add_end(end); + + uip_ipaddr_copy(&conn->ripaddr, &bcast_addr); + uip_send(uip_appdata, (int)(end - (u8_t *)uip_appdata)); + printf("NACK\n"); +} + +/*---------------------------------------------------------------------------*/ +PROCESS(dhcp_server_process, "DHCP server"); +/*---------------------------------------------------------------------------*/ + +PROCESS_THREAD(dhcp_server_process, ev , data) +{ + static struct uip_udp_conn *conn; + static struct uip_udp_conn *send_conn; + static struct dhcps_client_lease *lease; + PROCESS_BEGIN(); + printf("DHCP server starting\n"); + uip_ipaddr(&any_addr, 0,0,0,0); + uip_ipaddr(&bcast_addr, 255,255,255,255); + conn = udp_new(&any_addr, HTONS(DHCPS_CLIENT_PORT), NULL); + if (!conn) goto exit; + send_conn = udp_new(&bcast_addr, HTONS(DHCPS_CLIENT_PORT), NULL); + if (!send_conn) goto exit; + + uip_udp_bind(conn, HTONS(DHCPS_SERVER_PORT)); + uip_udp_bind(send_conn, HTONS(DHCPS_SERVER_PORT)); + while(1) { + PROCESS_WAIT_EVENT(); + if(ev == tcpip_event) { + if (uip_newdata()) { + struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; + struct uip_udpip_hdr *header = (struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN]; + + if (m->op == DHCP_REQUEST && check_cookie() && m->hlen <= MAX_HLEN) { + uint8_t *opt = find_option(DHCP_OPTION_MSG_TYPE); + if (opt) { + uint8_t mtype = opt[2]; + if (opt[2] == DHCPDISCOVER) { + printf("Discover\n"); + lease = choose_address(); + if (lease) { + lease->lease_end = clock_seconds()+config->default_lease_time; + tcpip_poll_udp(send_conn); + PROCESS_WAIT_EVENT_UNTIL(uip_poll()); + send_offer(conn,lease); + } + } else { + uint8_t *opt = find_option(DHCP_OPTION_SERVER_ID); + if (!opt || uip_ipaddr_cmp((uip_ipaddr_t*)&opt[2], &uip_hostaddr)) { + if (mtype == DHCPREQUEST) { + printf("Request\n"); + lease = allocate_address(); + tcpip_poll_udp(send_conn); + PROCESS_WAIT_EVENT_UNTIL(uip_poll()); + if (!lease) { + send_nack(send_conn); + } else { + send_ack(send_conn,lease); + } + } else if (mtype == DHCPRELEASE) { + printf("Release\n"); + release_address(); + } else if (mtype == DHCPDECLINE) { + printf("Decline\n"); + } else if (mtype == DHCPINFORM) { + printf("Inform\n"); + } + } + } + } + } + } + } else if (uip_poll()) { + + } + } + exit: + printf("DHCP server exiting\n"); + PROCESS_END(); +} + +void +dhcps_init(const struct dhcps_config *conf) +{ + config = conf; + process_start(&dhcp_server_process,NULL); +} diff --git a/cpu/arm/common/usb/cdc-eth/dhcps.h b/cpu/arm/common/usb/cdc-eth/dhcps.h new file mode 100644 index 000000000..d8de26d3a --- /dev/null +++ b/cpu/arm/common/usb/cdc-eth/dhcps.h @@ -0,0 +1,47 @@ +#ifndef __DHCPS_H__6M2XYUGNTK__ +#define __DHCPS_H__6M2XYUGNTK__ +#include "contiki-net.h" +#include + +#define MAX_HLEN 6 + +struct dhcps_client_lease +{ + uint8_t chaddr[MAX_HLEN]; + uip_ipaddr_t ipaddr; + unsigned long lease_end; + uint8_t flags; +}; + +struct dhcps_config +{ + unsigned long default_lease_time; + uip_ipaddr_t netmask; + uip_ipaddr_t dnsaddr; + uip_ipaddr_t default_router; + struct dhcps_client_lease *leases; + uint8_t flags; + uint8_t num_leases; +}; + +#define DHCP_CONF_NETMASK 0x01 +#define DHCP_CONF_DNSADDR 0x02 +#define DHCP_CONF_DEFAULT_ROUTER 0x04 + +#define DHCP_INIT_LEASE(addr0, addr1, addr2, addr3) \ +{{0},{addr0, addr1, addr2, addr3},0,0} + +/** + * Start the DHCP server + * + * This function starts th DHCP server with the given configuration. + * The flags field determines which options are actually sent to the + * client + * + * \param conf Pointer to a configuration struct. The configuration is + * not copied and should remain constant while the server is running. + * The leases pointed to by the configuration must be in writable memory. + **/ +void dhcps_init(const struct dhcps_config *conf); + +#endif /* __DHCPS_H__6M2XYUGNTK__ */