diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-10-25 16:28:08 -0600 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-10-25 16:28:08 -0600 |
commit | 9f4494685a29714c57cc11d62dead71f7004e061 (patch) | |
tree | 32976be279a3fd89a26f382cd3a358c66f9cd726 /libdhcp | |
parent | 84051eb54834ff805fee1c2e0f573d4433a254c2 (diff) |
ahhh
Diffstat (limited to 'libdhcp')
-rw-r--r-- | libdhcp/dhcp.c | 255 | ||||
-rw-r--r-- | libdhcp/include/libdhcp/dhcp.h | 36 |
2 files changed, 126 insertions, 165 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++; -} diff --git a/libdhcp/include/libdhcp/dhcp.h b/libdhcp/include/libdhcp/dhcp.h index e6b1801..aae4a4d 100644 --- a/libdhcp/include/libdhcp/dhcp.h +++ b/libdhcp/include/libdhcp/dhcp.h @@ -70,14 +70,6 @@ #include <libmisc/net.h> #include "hw/w5500.h" -struct dhcp_lease { - struct net_ip4_addr addr; - struct net_ip4_addr subnet_mask; - struct net_ip4_addr gateway; - struct net_ip4_addr dns; - uint32_t lifetime; /* in seconds, except 0xffffffff is "infinity" */ -}; - enum dhcp_event { DHCP_ASSIGN, DHCP_UPDATE, @@ -135,4 +127,32 @@ uint8_t DHCP_run(struct w5500 *chip, uint8_t socknum, dhcp_callback_t cb); */ void DHCP_stop(implements_net_packet_conn *sock); +void xhandle(uint8_t opt_typ, uint8_t opt_len, uint8_t *opt_dat) { + switch (opt_typ) { + case DHCP_OPT_SUBNET_MASK: + if (opt_len != 4) + return; + global_lease.subnet_mask.octets[0] = opt_dat[0]; + global_lease.subnet_mask.octets[1] = opt_dat[1]; + global_lease.subnet_mask.octets[2] = opt_dat[2]; + global_lease.subnet_mask.octets[3] = opt_dat[3]; + case DHCP_OPT_ROUTER : + if (opt_len < 4) + return; + global_lease.gateway.octets[0] = opt_dat[0]; + global_lease.gateway.octets[1] = opt_dat[1]; + global_lease.gateway.octets[2] = opt_dat[2]; + global_lease.gateway.octets[3] = opt_dat[3]; + break; + case DHCP_OPT_DOMAIN_SERVER : + if (opt_len < 4) + return; + global_lease.dns.octets[0] = opt_dat[0]; + global_lease.dns.octets[1] = opt_dat[1]; + global_lease.dns.octets[2] = opt_dat[2]; + global_lease.dns.octets[3] = opt_dat[3]; + break; + } +} + #endif /* _LIBDHCP_DHCP_H_ */ |