summaryrefslogtreecommitdiff
path: root/libdhcp/dhcp_client.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdhcp/dhcp_client.c')
-rw-r--r--libdhcp/dhcp_client.c63
1 files changed, 36 insertions, 27 deletions
diff --git a/libdhcp/dhcp_client.c b/libdhcp/dhcp_client.c
index 4c4ece3..1b4bf61 100644
--- a/libdhcp/dhcp_client.c
+++ b/libdhcp/dhcp_client.c
@@ -64,32 +64,24 @@
* SPDX-License-Identifier: MIT
*/
-/* IPv4:
+/* Implemented:
* - DHCPv4: https://datatracker.ietf.org/doc/html/rfc2131
- * - Auto-IP: https://datatracker.ietf.org/doc/html/rfc3927
- * - DNAv4: https://datatracker.ietf.org/doc/html/rfc4436
- *
- * This implmementation does NOT support RFC 4361 and thus cannot
- * support RFC 6842.
- *
- * - DHCPv4 node-specific client identifiers: https://datatracker.ietf.org/doc/html/rfc4361
+ * - DHCPv4 long options: https://datatracker.ietf.org/doc/html/rfc3396
* - DHCPv4 client identifiers in replies: https://datatracker.ietf.org/doc/html/rfc6842
*
- * This implementation does NOT support split options (originally RFC
- * 2131, but clarified in RFC 3396).
+ * TODO:
+ * - AutoIPv4: https://datatracker.ietf.org/doc/html/rfc3927
+ * - mDNS responder: https://datatracker.ietf.org/doc/html/rfc6762
*
- * - DHCPv4 long options: https://datatracker.ietf.org/doc/html/rfc3396
+ * Not implemented:
+ * - DHCPv4 node-specific client identifiers: https://datatracker.ietf.org/doc/html/rfc4361
+ * - DNAv4: https://datatracker.ietf.org/doc/html/rfc4436
+ * - LLMNR responder: https://datatracker.ietf.org/doc/html/rfc4795
*
-
- * IPv6:
+ * Not implemented, because the W5500 doesn't support IPv6:
* - SLAAC: https://datatracker.ietf.org/doc/html/rfc2462
* - DNAv6: https://datatracker.ietf.org/doc/html/rfc6059
- *
- * Common:
- * - NetBIOS name resolution: https://datatracker.ietf.org/doc/html/rfc1001
- * https://datatracker.ietf.org/doc/html/rfc1002
- * - LLMNR: https://datatracker.ietf.org/doc/html/rfc4795
- * - mDNS: https://datatracker.ietf.org/doc/html/rfc6762
+ * - DHCPv6: https://datatracker.ietf.org/doc/html/rfc8415
*/
#include <string.h> /* for strlen(), memcpy(), memset() */
@@ -141,6 +133,8 @@ struct dhcp_client {
implements_net_packet_conn *sock;
struct net_eth_addr self_eth_addr;
char self_hostname[63];
+ size_t self_id_len;
+ uint8_t *self_id_dat;
/* Mutable. */
enum {
@@ -331,7 +325,7 @@ static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, char *e
[DHCP_OPT_ADDRESS_TIME] = { 1, { MAY, MUST_NOT, MAY, MUST_NOT, MUST_NOT }, NONE },
[DHCP_OPT_OVERLOAD] = { 1, { MAY, MAY, MAY, MAY, MAY }, NONE },
[DHCP_OPT_DHCP_MSG_TYPE] = { 1, { MUST, MUST, MUST, MUST, MUST }, V(msgtyp) },
- [DHCP_OPT_CLIENT_ID] = { 1, { MAY, MAY, MAY, MAY, MAY }, NONE },
+ [DHCP_OPT_CLIENT_ID] = { 1, { MAY, MAY, MAY, MAY, MAY }, client->self_id_len, client->self_id_dat },
[DHCP_OPT_CLASS_ID] = { 1, { MAY, MAY, MAY, MUST_NOT, MUST_NOT }, NONE },
[DHCP_OPT_DHCP_SERVER_ID] = { 1, { MUST_NOT, MUST_NOT, INC_SERVER, MUST, MUST }, V(client->lease_server_id) },
[DHCP_OPT_PARAMETER_LIST] = { 1, { MAY, MAY, MAY, MUST_NOT, MUST_NOT }, V(parameter_request_list) },
@@ -369,11 +363,17 @@ static bool dhcp_client_send(struct dhcp_client *client, uint8_t msgtyp, char *e
case SHOULD_NOT:
case MAY:
if (options[opt].val_len) {
- assert(options[opt].val_len <= UINT8_MAX);
- msg.options[optlen++] = opt;
- msg.options[optlen++] = options[opt].val_len;
- memcpy(&msg.options[optlen], options[opt].val_ptr, options[opt].val_len);
- optlen += options[opt].val_len;
+ assert(options[opt].val_len <= UINT16_MAX);
+ for (size_t done = 0; done < options[opt].val_len;) {
+ uint8_t len = options[opt].val_len - done > UINT8_MAX
+ ? UINT8_MAX
+ : options[opt].val_len - done;
+ msg.options[optlen++] = opt;
+ msg.options[optlen++] = len;
+ memcpy(&msg.options[optlen], &((char*)options[opt].val_ptr)[done], len);
+ optlen += len;
+ done += len;
+ }
}
break;
case _SHOULD_NOT_HAPPEN:
@@ -562,7 +562,8 @@ static ssize_t dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg
enum requirement cols[3];
} option_req[0x100] = {
/* Enocde the table from
- * https://datatracker.ietf.org/doc/html/rfc2131#page-29 */
+ * https://datatracker.ietf.org/doc/html/rfc2131#page-29, with modifications from
+ * https://datatracker.ietf.org/doc/html/rfc6842#page-4 */
#define REQ_TIME client->last_sent_msgtyp == DHCP_MSGTYP_REQUEST ? MUST : MUST_NOT
/* Option DHCPOFFER DHCPACK DHCPNAK */
/* ------ -------- ---------- -------- */
@@ -572,7 +573,7 @@ static ssize_t dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg
[DHCP_OPT_DHCP_MSG_TYPE] = { 1, { MUST, MUST, MUST } },
[DHCP_OPT_PARAMETER_LIST] = { 1, { MUST_NOT, MUST_NOT, MUST_NOT } },
[DHCP_OPT_DHCP_MESSAGE] = { 1, { SHOULD, SHOULD, SHOULD } },
- [DHCP_OPT_CLIENT_ID] = { 1, { MUST_NOT, MUST_NOT, MAY } },
+ [DHCP_OPT_CLIENT_ID] = { 1, { MAY, MAY, MAY } }, /* MUST_NOTs changed to MAY, per RFC 6842 */
[DHCP_OPT_CLASS_ID] = { 1, { MAY, MAY, MAY } },
[DHCP_OPT_DHCP_SERVER_ID] = { 1, { MUST, MUST, MUST } },
[DHCP_OPT_DHCP_MAX_MSG_SIZE] = { 1, { MUST_NOT, MUST_NOT, MUST_NOT } },
@@ -609,6 +610,14 @@ static ssize_t dhcp_client_recv(struct dhcp_client *client, struct dhcp_recv_msg
assert_notreached("bad table");
}
}
+ /* Validate values of options. */
+ if (ret->options[DHCP_OPT_CLASS_ID].len) {
+ /* https://datatracker.ietf.org/doc/html/rfc6842#page-4 */
+ if (ret->options[DHCP_OPT_CLASS_ID].len != client->self_id_len)
+ goto ignore;
+ if (memcmp(ret->options[DHCP_OPT_CLASS_ID].dat, client->self_id_dat, client->self_id_len))
+ goto ignore;
+ }
return 0;
}