mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-10-29 17:54:14 +08:00
rtl837x_port.c prints "called" and "done" around mirroring, PVID, VLAN and L2 setup, and dhcp.c around discover, request, start and stop. They land on the console on every boot and config replay, and in the log once syslog is running. The VLAN line keeps the VLAN, members and tagged values, only without the function name in front. On the KP_9000_6XHML_X2 this takes 359 bytes out of BANK1, 88 out of BANK2 and 24 out of BANK3. BANK1 goes from 431 to 790 bytes free.
424 lines
12 KiB
C
424 lines
12 KiB
C
/*
|
|
* This is a DHCP client implementation for the RTL837x-based switches
|
|
*/
|
|
|
|
// #define REGDBG
|
|
// #define DEBUG
|
|
|
|
#include <stdint.h>
|
|
#include "rtl837x_sfr.h"
|
|
#include "rtl837x_common.h"
|
|
#include "dhcp.h"
|
|
#include "uip.h"
|
|
#include "uip/uip.h"
|
|
|
|
__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_HOSTNAME 12
|
|
#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 BANK3
|
|
#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_appdata)
|
|
#define DHCP_OPT ((__xdata uint8_t *)(uip_appdata) + sizeof (struct dhcp_pkt))
|
|
|
|
__xdata uint32_t long_value;
|
|
|
|
|
|
void dhcp_print_ip(__xdata 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 = 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);
|
|
memcpy(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;
|
|
memcpy(&DHCP_OPT[dhcp_state.opt_ptr], uip_ethaddr.addr, 6);
|
|
dhcp_state.opt_ptr += 6;
|
|
}
|
|
|
|
|
|
void dhcp_addopt_hostname(void)
|
|
{
|
|
uint8_t len = 0;
|
|
while (hostname[len])
|
|
len++;
|
|
if (!len)
|
|
return;
|
|
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_HOSTNAME;
|
|
DHCP_OPT[dhcp_state.opt_ptr++] = len;
|
|
memcpy(&DHCP_OPT[dhcp_state.opt_ptr], hostname, len);
|
|
dhcp_state.opt_ptr += len;
|
|
}
|
|
|
|
|
|
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];
|
|
memcpy(&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];
|
|
memcpy(&DHCP_OPT[dhcp_state.opt_ptr], uip_ethaddr.addr, 4);
|
|
}
|
|
|
|
|
|
void dhcp_send_discover(void)
|
|
{
|
|
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_addopt_hostname();
|
|
|
|
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)
|
|
{
|
|
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_addopt_hostname();
|
|
|
|
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(__xdata uint8_t * 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 != 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]);
|
|
/* T1 is optional. Without it the renewal time stays zero, which
|
|
* makes dhcp_timer zero, and the callback then sends a REQUEST on
|
|
* every pass through LEASING: client and server trade REQUEST and
|
|
* ACK as fast as the round trip allows. RFC 2131 has the client
|
|
* renew at half the lease when the server does not say, and if
|
|
* there is no lease either, pick something rather than zero. Only
|
|
* filled in when absent, so a server that asks for a short renewal
|
|
* still gets it. */
|
|
if (!dhcp_state.renewal)
|
|
dhcp_state.renewal = dhcp_state.lease / 2;
|
|
if (!dhcp_state.renewal)
|
|
dhcp_state.renewal = 60;
|
|
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
|
|
{
|
|
/* Starting twice would leave the first socket bound: uip_udp_new() takes
|
|
* the next free slot while the old one keeps port 68, and dhcp_callback()
|
|
* matches on that port rather than on the connection, so every leftover
|
|
* runs the state machine too and the timers count down once per socket. */
|
|
if (dhcp_state.state != DHCP_OFF)
|
|
dhcp_stop();
|
|
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();
|
|
// Workaround SDCC bug 4070: dhcp_state.transaction_id = SFR_DATA_U32;
|
|
__xdata uint8_t * tid = &dhcp_state.transaction_id;
|
|
*tid++ = SFR_DATA_24;
|
|
*tid++ = SFR_DATA_16;
|
|
*tid++ = SFR_DATA_8;
|
|
*tid = SFR_DATA_0;
|
|
dhcp_state.state = DHCP_START;
|
|
}
|
|
|
|
|
|
void dhcp_stop(void) __banked
|
|
{
|
|
uip_udp_remove(dhcp_state.conn);
|
|
dhcp_state.state = DHCP_OFF;
|
|
}
|
|
|
|
|
|
void dhcp_callback(uint16_t lport) __banked
|
|
{
|
|
if (lport != HTONS(DHCPC_CLIENT_PORT)) // Is this call for us? If not, ignore it
|
|
return;
|
|
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;
|
|
}
|