summaryrefslogtreecommitdiff
path: root/libdhcp/dhcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdhcp/dhcp.c')
-rw-r--r--libdhcp/dhcp.c255
1 files changed, 98 insertions, 157 deletions
diff --git a/libdhcp/dhcp.c b/libdhcp/dhcp.c
index bba61b9..2fc7724 100644
--- a/libdhcp/dhcp.c
+++ b/libdhcp/dhcp.c
@@ -96,7 +96,7 @@ struct dhcp_msg {
uint8_t hlen; /* length of ->chaddr (`sizeof(struct net_eth_addr)`) */
uint8_t hops;
- uint32be_t xid; /* `global_xid`; this increase one every DHCP transaction */
+ uint32be_t xid; /* transaction ID */
uint16be_t secs;
uint16be_t flags; /* DHCP_FLAG_{x} */
@@ -250,8 +250,6 @@ int8_t dhcp_state = STATE_DHCP_INIT; /* DHCP state */
int8_t dhcp_retry_count = 0;
volatile uint32_t dhcp_tick_1s = 0; /* unit 1 second */
uint32_t dhcp_tick_next = DHCP_WAIT_TIME ;
-uint32_t global_xid; /* Any number */
-struct dhcp_msg *pDHCPMSG; /* Buffer pointer for DHCP processing */
char global_hostname[64];
struct net_eth_addr global_eth_addr; /* DHCP Client MAC address. */
@@ -268,26 +266,30 @@ static inline size_t str_encode(void *dst, char *str) {
}
/* make the common DHCP message */
-static void dhcp_msg_init(struct dhcp_msg *msg, size_t *optlen) {
+static inline void dhcp_msg_init(struct dhcp_msg *msg, size_t *optlen,
+ struct net_eth_addr self_eth_addr,
+ uint16_t flags, uint32_t xid) {
size_t tmp;
assert(msg);
assert(optlen);
+ *msg = (struct dhcp_msg){0};
+
msg->op = DHCP_OP_BOOTREQUEST;
msg->htype = DHCP_HTYPE_ETHERNET;
- msg->hlen = sizeof(global_eth_addr);
+ msg->hlen = sizeof(self_eth_addr);
msg->hops = CONFIG_DHCP_HOPS;
- msg->xid = uint32be_marshal(global_xid);
+ msg->xid = uint32be_marshal(xid);
msg->secs = uint16be_marshal(CONFIG_DHCP_SECS);
- msg->flags = uint16be_marshal(DHCP_FLAG_BROADCAST);
+ msg->flags = uint16be_marshal(flags);
msg->ciaddr = (struct net_ip4_addr){0};
msg->yiaddr = (struct net_ip4_addr){0};
msg->siaddr = (struct net_ip4_addr){0};
msg->siaddr = (struct net_ip4_addr){0};
msg->giaddr = (struct net_ip4_addr){0};
- tmp = mem_encode(msg->chaddr, global_eth_addr);
+ tmp = mem_encode(msg->chaddr, self_eth_addr);
memset(&msg->chaddr[tmp], 0, sizeof(msg->chaddr)-tmp);
memset(msg->sname, 0, sizeof(msg->sname));
@@ -301,57 +303,60 @@ static void dhcp_msg_init(struct dhcp_msg *msg, size_t *optlen) {
}
static void dhcp_send_DISCOVER(implements_net_packet_conn *sock) {
+ struct dhcp_msg msg;
size_t k;
- dhcp_msg_init(pDHCPMSG, &k);
+ dhcp_msg_init(&msg, &k, DHCP_FLAG_BROADCAST);
DHCP_SIP = (struct net_ip4_addr){0};
DHCP_REAL_SIP = (struct net_ip4_addr){0};
/* Message type. */
- pDHCPMSG->options[k++] = DHCP_OPT_DHCP_MSG_TYPE;
- pDHCPMSG->options[k++] = 1;
- pDHCPMSG->options[k++] = DHCP_MSGTYP_DISCOVER;
+ msg->options[k++] = DHCP_OPT_DHCP_MSG_TYPE;
+ msg->options[k++] = 1;
+ msg->options[k++] = DHCP_MSGTYP_DISCOVER;
/* Our Client ID. */
- pDHCPMSG->options[k++] = DHCP_OPT_CLIENT_ID;
- pDHCPMSG->options[k++] = 1+sizeof(global_eth_addr);
- pDHCPMSG->options[k++] = DHCP_HTYPE_ETHERNET;
- k += mem_encode(&pDHCPMSG->options[k], global_eth_addr);
+ msg->options[k++] = DHCP_OPT_CLIENT_ID;
+ msg->options[k++] = 1+sizeof(self_eth_addr);
+ msg->options[k++] = DHCP_HTYPE_ETHERNET;
+ k += mem_encode(&msg->options[k], self_eth_addr);
/* Our requested hostname. */
- pDHCPMSG->options[k++] = DHCP_OPT_HOSTNAME;
- pDHCPMSG->options[k++] = strlen(global_hostname);
- k += str_encode(&pDHCPMSG->options[k], global_hostname);
+ msg->options[k++] = DHCP_OPT_HOSTNAME;
+ msg->options[k++] = strlen(global_hostname);
+ k += str_encode(&msg->options[k], global_hostname);
/* Which parameters we want back. */
- pDHCPMSG->options[k++] = DHCP_OPT_PARAMETER_LIST;
- pDHCPMSG->options[k++] = 6;
- pDHCPMSG->options[k++] = DHCP_OPT_SUBNET_MASK; /* 1 */
- pDHCPMSG->options[k++] = DHCP_OPT_ROUTER; /* 2 */
- pDHCPMSG->options[k++] = DHCP_OPT_DOMAIN_SERVER; /* 3 */
- pDHCPMSG->options[k++] = DHCP_OPT_DOMAIN_NAME; /* 4 */
- pDHCPMSG->options[k++] = DHCP_OPT_RENEWAL_TIME; /* 5 */
- pDHCPMSG->options[k++] = DHCP_OPT_REBINDING_TIME; /* 6 */
+ msg->options[k++] = DHCP_OPT_PARAMETER_LIST;
+ msg->options[k++] = 6;
+ msg->options[k++] = DHCP_OPT_SUBNET_MASK; /* 1 */
+ msg->options[k++] = DHCP_OPT_ROUTER; /* 2 */
+ msg->options[k++] = DHCP_OPT_DOMAIN_SERVER; /* 3 */
+ msg->options[k++] = DHCP_OPT_DOMAIN_NAME; /* 4 */
+ msg->options[k++] = DHCP_OPT_RENEWAL_TIME; /* 5 */
+ msg->options[k++] = DHCP_OPT_REBINDING_TIME; /* 6 */
/* End. */
- pDHCPMSG->options[k++] = DHCP_OPT_END;
+ msg->options[k++] = DHCP_OPT_END;
+ assert(k <= CONFIG_DHCP_OPT_SIZE);
+ /* Send. */
debugf("> Send DHCP_DISCOVER");
- assert(k <= CONFIG_DHCP_OPT_SIZE);
- VCALL(sock, sendto, pDHCPMSG, DHCP_MSG_BASE_SIZE + k, net_ip4_addr_broadcast, DHCP_PORT_SERVER);
+ VCALL(sock, sendto, msg, DHCP_MSG_BASE_SIZE + k, net_ip4_addr_broadcast, DHCP_PORT_SERVER);
}
static void dhcp_send_REQUEST(implements_net_packet_conn *sock) {
struct net_ip4_addr ip;
+ struct dhcp_msg msg;
size_t k;
- dhcp_msg_init(pDHCPMSG, &k);
+ dhcp_msg_init(msg, &k,
+ (dhcp_state != STATE_DHCP_LEASED && dhcp_state != STATE_DHCP_REREQUEST) ? DHCP_FLAG_BROADCAST : 0);
switch (dhcp_state) {
case STATE_DHCP_LEASED:
case STATE_DHCP_REREQUEST:
- pDHCPMSG->flags = uint16be_marshal(0);
- pDHCPMSG->ciaddr = global_lease.addr;
+ msg->ciaddr = global_lease.addr;
ip = DHCP_SIP;
break;
default:
@@ -359,59 +364,59 @@ static void dhcp_send_REQUEST(implements_net_packet_conn *sock) {
}
/* Message type. */
- pDHCPMSG->options[k++] = DHCP_OPT_DHCP_MSG_TYPE;
- pDHCPMSG->options[k++] = 1;
- pDHCPMSG->options[k++] = DHCP_MSGTYP_REQUEST;
+ msg->options[k++] = DHCP_OPT_DHCP_MSG_TYPE;
+ msg->options[k++] = 1;
+ msg->options[k++] = DHCP_MSGTYP_REQUEST;
/* Our Client ID. */
- pDHCPMSG->options[k++] = DHCP_OPT_CLIENT_ID;
- pDHCPMSG->options[k++] = 1+sizeof(global_eth_addr);
- pDHCPMSG->options[k++] = DHCP_HTYPE_ETHERNET;
- k += mem_encode(&pDHCPMSG->options[k], global_eth_addr);
+ msg->options[k++] = DHCP_OPT_CLIENT_ID;
+ msg->options[k++] = 1+sizeof(self_eth_addr);
+ msg->options[k++] = DHCP_HTYPE_ETHERNET;
+ k += mem_encode(&msg->options[k], self_eth_addr);
switch (dhcp_state) {
case STATE_DHCP_LEASED:
case STATE_DHCP_REREQUEST:
/* Our current IP address. */
- pDHCPMSG->options[k++] = DHCP_OPT_ADDRESS_REQUEST;
- pDHCPMSG->options[k++] = sizeof(global_lease.addr);
- k += mem_encode(&pDHCPMSG->options[k], global_lease.addr);
+ msg->options[k++] = DHCP_OPT_ADDRESS_REQUEST;
+ msg->options[k++] = sizeof(global_lease.addr);
+ k += mem_encode(&msg->options[k], global_lease.addr);
/* The server we got it from. */
- pDHCPMSG->options[k++] = DHCP_OPT_DHCP_SERVER_ID;
- pDHCPMSG->options[k++] = sizeof(DHCP_SIP);
- k += mem_encode(&pDHCPMSG->options[k], DHCP_SIP);
+ msg->options[k++] = DHCP_OPT_DHCP_SERVER_ID;
+ msg->options[k++] = sizeof(DHCP_SIP);
+ k += mem_encode(&msg->options[k], DHCP_SIP);
}
/* Our requested hostname. */
- pDHCPMSG->options[k++] = DHCP_OPT_HOSTNAME;
- pDHCPMSG->options[k++] = strlen(global_hostname);
- k += str_encode(&pDHCPMSG->options[k], global_hostname);
+ msg->options[k++] = DHCP_OPT_HOSTNAME;
+ msg->options[k++] = strlen(global_hostname);
+ k += str_encode(&msg->options[k], global_hostname);
/* Which parameters we want back. */
- pDHCPMSG->options[k++] = DHCP_OPT_PARAMETER_LIST;
- pDHCPMSG->options[k++] = 8;
- pDHCPMSG->options[k++] = DHCP_OPT_SUBNET_MASK; /* 1 */
- pDHCPMSG->options[k++] = DHCP_OPT_ROUTER; /* 2 */
- pDHCPMSG->options[k++] = DHCP_OPT_DOMAIN_SERVER; /* 3 */
- pDHCPMSG->options[k++] = DHCP_OPT_DOMAIN_NAME; /* 4 */
- pDHCPMSG->options[k++] = DHCP_OPT_RENEWAL_TIME; /* 5 */
- pDHCPMSG->options[k++] = DHCP_OPT_REBINDING_TIME; /* 6 */
- pDHCPMSG->options[k++] = DHCP_OPT_ROUTER_DISCOVERY; /* 7 */
- pDHCPMSG->options[k++] = DHCP_OPT_STATIC_ROUTE; /* 8 */
+ msg->options[k++] = DHCP_OPT_PARAMETER_LIST;
+ msg->options[k++] = 8;
+ msg->options[k++] = DHCP_OPT_SUBNET_MASK; /* 1 */
+ msg->options[k++] = DHCP_OPT_ROUTER; /* 2 */
+ msg->options[k++] = DHCP_OPT_DOMAIN_SERVER; /* 3 */
+ msg->options[k++] = DHCP_OPT_DOMAIN_NAME; /* 4 */
+ msg->options[k++] = DHCP_OPT_RENEWAL_TIME; /* 5 */
+ msg->options[k++] = DHCP_OPT_REBINDING_TIME; /* 6 */
+ msg->options[k++] = DHCP_OPT_ROUTER_DISCOVERY; /* 7 */
+ msg->options[k++] = DHCP_OPT_STATIC_ROUTE; /* 8 */
/* End. */
- pDHCPMSG->options[k++] = DHCP_OPT_END;
+ msg->options[k++] = DHCP_OPT_END;
+ assert(k <= CONFIG_DHCP_OPT_SIZE);
debugf("> Send DHCP_REQUEST");
- assert(k <= CONFIG_DHCP_OPT_SIZE);
- VCALL(sock, sendto, pDHCPMSG, DHCP_MSG_BASE_SIZE + k, ip, DHCP_PORT_SERVER);
+ VCALL(sock, sendto, msg, DHCP_MSG_BASE_SIZE + k, ip, DHCP_PORT_SERVER);
}
static void dhcp_send_DECLINE(implements_net_packet_conn *sock) {
size_t k;
- dhcp_msg_init(pDHCPMSG, &k);
+ dhcp_msg_init(pDHCPMSG, &k, DHCP_FLAG_BROADCAST);
pDHCPMSG->flags = uint16be_marshal(0);
/* Option Request Param. */
@@ -421,10 +426,10 @@ static void dhcp_send_DECLINE(implements_net_packet_conn *sock) {
/* Our Client ID. */
pDHCPMSG->options[k++] = DHCP_OPT_CLIENT_ID;
- pDHCPMSG->options[k++] = 1+sizeof(global_eth_addr);
+ pDHCPMSG->options[k++] = 1+sizeof(self_eth_addr);
pDHCPMSG->options[k++] = DHCP_HTYPE_ETHERNET;
- memcpy(&pDHCPMSG->options[k], global_eth_addr.octets, sizeof(global_eth_addr));
- k += sizeof(global_eth_addr);
+ memcpy(&pDHCPMSG->options[k], self_eth_addr.octets, sizeof(self_eth_addr));
+ k += sizeof(self_eth_addr);
/* Our current IP address. */
pDHCPMSG->options[k++] = DHCP_OPT_ADDRESS_REQUEST;
@@ -456,7 +461,7 @@ static int8_t dhcp_msg_parse(implements_net_packet_conn *sock) {
return 0;
}
/* Compare our MAC address. */
- if (memcmp(pDHCPMSG->chaddr, global_eth_addr.octets, sizeof(global_eth_addr))) {
+ if (memcmp(pDHCPMSG->chaddr, self_eth_addr.octets, sizeof(self_eth_addr))) {
debugf("Not my DHCP Message. This message is ignored.");
return 0;
}
@@ -482,6 +487,7 @@ static int8_t dhcp_msg_parse(implements_net_packet_conn *sock) {
break;
default:
opt_len = pDHCPMSG->options[k++];
+ xhandle(opt_typ, opt_len, &pDHCPMSG->options[k]);
}
switch (opt_typ) {
case DHCP_OPT_DHCP_MSG_TYPE:
@@ -489,30 +495,6 @@ static int8_t dhcp_msg_parse(implements_net_packet_conn *sock) {
continue;
msg_type = pDHCPMSG->options[k];
break;
- case DHCP_OPT_SUBNET_MASK:
- if (opt_len != 4)
- continue;
- global_lease.subnet_mask.octets[0] = pDHCPMSG->options[k+0];
- global_lease.subnet_mask.octets[1] = pDHCPMSG->options[k+1];
- global_lease.subnet_mask.octets[2] = pDHCPMSG->options[k+2];
- global_lease.subnet_mask.octets[3] = pDHCPMSG->options[k+3];
- break;
- case DHCP_OPT_ROUTER :
- if (opt_len < 4)
- continue;
- global_lease.gateway.octets[0] = pDHCPMSG->options[k+0];
- global_lease.gateway.octets[1] = pDHCPMSG->options[k+1];
- global_lease.gateway.octets[2] = pDHCPMSG->options[k+2];
- global_lease.gateway.octets[3] = pDHCPMSG->options[k+3];
- break;
- case DHCP_OPT_DOMAIN_SERVER :
- if (opt_len < 4)
- continue;
- global_lease.dns.octets[0] = pDHCPMSG->options[k+0];
- global_lease.dns.octets[1] = pDHCPMSG->options[k+1];
- global_lease.dns.octets[2] = pDHCPMSG->options[k+2];
- global_lease.dns.octets[3] = pDHCPMSG->options[k+3];
- break;
case DHCP_OPT_ADDRESS_TIME:
if (opt_len != 4)
continue;
@@ -613,21 +595,35 @@ static int8_t dhcp_check_leasedIP(implements_net_packet_conn *sock) {
return 0;
}
-uint8_t DHCP_run(struct w5500 *chip, uint8_t socknum, dhcp_callback_t cb) {
- uint8_t msg_type;
- uint8_t ret;
+COROUTINE DHCP_cr(struct w5500 *chip, uint8_t socknum,
+ struct net_eth_addr self_eth_addr,
+ char *self_hostname,
+ dhcp_callback_t cb) {
+ uint32_t xid;
+ implements_net_packet_conn *sock;
+
+ xid = 0x12345678;
+ xid += self_eth_addr.octets[3];
+ xid += self_eth_addr.octets[4];
+ xid += self_eth_addr.octets[5];
+ xid += (self_eth_addr.octets[3] ^
+ self_eth_addr.octets[4] ^
+ self_eth_addr.octets[5]);
- if (dhcp_state == STATE_DHCP_STOP)
- return DHCP_RET_STOPPED;
+ dhcp_tick_1s = 0;
+ dhcp_tick_next = DHCP_WAIT_TIME;
+ dhcp_retry_count = 0;
+ dhcp_state = STATE_DHCP_INIT;
- implements_net_packet_conn *sock = w5500_udp_conn(chip, socknum, DHCP_PORT_CLIENT);
+ sock = w5500_udp_conn(chip, socknum, DHCP_PORT_CLIENT);
- ret = DHCP_RET_RUNNING;
- msg_type = dhcp_msg_parse(sock);
+ ret = DHCP_RET_RUNNING;
+ msg_type = dhcp_msg_parse(sock);
- switch ( dhcp_state ) {
+ for (;;) {
+ /* State transition diagram: https://datatracker.ietf.org/doc/html/rfc2131#page-35 */
+ switch (state) {
case STATE_DHCP_INIT:
- global_lease.addr = net_ip4_addr_zero;
dhcp_send_DISCOVER(sock);
dhcp_state = STATE_DHCP_DISCOVER;
break;
@@ -675,7 +671,7 @@ uint8_t DHCP_run(struct w5500 *chip, uint8_t socknum, dhcp_callback_t cb) {
msg_type = 0;
OLD_allocated_ip = global_lease.addr;
- global_xid++;
+ xid++;
dhcp_send_REQUEST(sock);
@@ -712,58 +708,3 @@ uint8_t DHCP_run(struct w5500 *chip, uint8_t socknum, dhcp_callback_t cb) {
return ret;
}
-
-void DHCP_stop(implements_net_packet_conn *sock) {
- VCALL(sock, close);
- dhcp_state = STATE_DHCP_STOP;
-}
-
-void DHCP_init(void *buf) {
- getSHAR(global_eth_addr);
- if (memcmp(global_eth_addr.octets, ((struct net_eth_addr){0}).octets, sizeof(struct net_eth_addr)) == 0) {
- /* assigning temporary mac address, you should be set
- * SHAR before call this function. */
- global_eth_addr.octets[0] = 0x00;
- global_eth_addr.octets[1] = 0x08;
- global_eth_addr.octets[2] = 0xdc;
- global_eth_addr.octets[3] = 0x00;
- global_eth_addr.octets[4] = 0x00;
- global_eth_addr.octets[5] = 0x00;
- setSHAR(global_eth_addr);
- }
-
- global_hostname[0] = 'W';
- global_hostname[1] = 'I';
- global_hostname[2] = 'Z';
- global_hostname[3] = 'n';
- global_hostname[4] = 'e';
- global_hostname[5] = 't';
- global_hostname[6] = "0123456789ABCDEF"[(global_eth_addr.octets[3] >> 4)&0xF];
- global_hostname[7] = "0123456789ABCDEF"[(global_eth_addr.octets[3] >> 0)&0xF];
- global_hostname[8] = "0123456789ABCDEF"[(global_eth_addr.octets[4] >> 4)&0xF];
- global_hostname[9] = "0123456789ABCDEF"[(global_eth_addr.octets[4] >> 0)&0xF];
- global_hostname[10] = "0123456789ABCDEF"[(global_eth_addr.octets[5] >> 4)&0xF];
- global_hostname[11] = "0123456789ABCDEF"[(global_eth_addr.octets[5] >> 0)&0xF];
- global_hostname[12] = '\0';
-
- pDHCPMSG = buf;
-
- global_xid = 0x12345678;
- global_xid += global_eth_addr.octets[3];
- global_xid += global_eth_addr.octets[4];
- global_xid += global_eth_addr.octets[5];
- global_xid += (global_eth_addr.octets[3] ^
- global_eth_addr.octets[4] ^
- global_eth_addr.octets[5]);
-
- /* WIZchip Netinfo Clear */
- setSIPR(net_ip4_addr_zero);
- setGAR(net_ip4_addr_zero);
-
- dhcp_reset_timeout();
- dhcp_state = STATE_DHCP_INIT;
-}
-
-void DHCP_time_handler(void) {
- dhcp_tick_1s++;
-}