USB CDC-Ethernet class
This commit is contained in:
parent
659b3fb7d3
commit
c5e62b7205
122
cpu/arm/common/usb/cdc-eth/cdc-eth-descriptors.c
Normal file
122
cpu/arm/common/usb/cdc-eth/cdc-eth-descriptors.c
Normal file
@ -0,0 +1,122 @@
|
||||
#include "descriptors.h"
|
||||
#include <cdc-acm/cdc.h>
|
||||
#include <contiki-conf.h>
|
||||
#include <usb-arch.h>
|
||||
|
||||
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;
|
43
cpu/arm/common/usb/cdc-eth/cdc-eth-string-descriptors.c
Normal file
43
cpu/arm/common/usb/cdc-eth/cdc-eth-string-descriptors.c
Normal file
@ -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;
|
170
cpu/arm/common/usb/cdc-eth/cdc-eth.c
Normal file
170
cpu/arm/common/usb/cdc-eth/cdc-eth.c
Normal file
@ -0,0 +1,170 @@
|
||||
#include <cdc-eth.h>
|
||||
#include <usb-api.h>
|
||||
#include <uip_arp.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <net/uip-fw.h>
|
||||
|
||||
#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;
|
||||
}
|
13
cpu/arm/common/usb/cdc-eth/cdc-eth.h
Normal file
13
cpu/arm/common/usb/cdc-eth/cdc-eth.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef __CDC_ETH_H__NUI0ULFC7C__
|
||||
#define __CDC_ETH_H__NUI0ULFC7C__
|
||||
|
||||
#include <net/uip.h>
|
||||
|
||||
/* 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__ */
|
451
cpu/arm/common/usb/cdc-eth/dhcps.c
Normal file
451
cpu/arm/common/usb/cdc-eth/dhcps.c
Normal file
@ -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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <uip_arp.h>
|
||||
#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);
|
||||
}
|
47
cpu/arm/common/usb/cdc-eth/dhcps.h
Normal file
47
cpu/arm/common/usb/cdc-eth/dhcps.h
Normal file
@ -0,0 +1,47 @@
|
||||
#ifndef __DHCPS_H__6M2XYUGNTK__
|
||||
#define __DHCPS_H__6M2XYUGNTK__
|
||||
#include "contiki-net.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#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__ */
|
Loading…
Reference in New Issue
Block a user