u-boot/net/dhcpv6.h
Sean Edmond a0245818f7 net: dhcp6: Add DHCPv6 (DHCP for IPv6)
Adds DHCPv6 protocol to u-boot.

Allows for address assignement with DHCPv6 4-message exchange
(SOLICIT->ADVERTISE->REQUEST->REPLY).  Includes DHCPv6 options
required by RFC 8415.  Also adds DHCPv6 options required
for PXE boot.

Possible enhancements:
- Duplicate address detection on DHCPv6 assigned address
- IPv6 address assignement through SLAAC
- Sending/parsing other DHCPv6 options (NTP, DNS, etc...)

Signed-off-by: Sean Edmond <seanedmond@microsoft.com>
Reviewed-by: Ramon Fried <rfried.dev@gmail.com>
2023-05-05 17:48:44 -04:00

256 lines
7.8 KiB
C

/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (C) Microsoft Corporation
* Author: Sean Edmond <seanedmond@microsoft.com>
*
*/
#ifndef __DHCP6_H__
#define __DHCP6_H__
/* Message types */
#define DHCP6_MSG_SOLICIT 1
#define DHCP6_MSG_ADVERTISE 2
#define DHCP6_MSG_REQUEST 3
#define DHCP6_MSG_REPLY 7
/* Option Codes */
#define DHCP6_OPTION_CLIENTID 1
#define DHCP6_OPTION_SERVERID 2
#define DHCP6_OPTION_IA_NA 3
#define DHCP6_OPTION_IA_TA 4
#define DHCP6_OPTION_IAADDR 5
#define DHCP6_OPTION_ORO 6
#define DHCP6_OPTION_PREFERENCE 7
#define DHCP6_OPTION_ELAPSED_TIME 8
#define DHCP6_OPTION_STATUS_CODE 13
#define DHCP6_OPTION_OPT_BOOTFILE_URL 59
#define DHCP6_OPTION_OPT_BOOTFILE_PARAM 60
#define DHCP6_OPTION_SOL_MAX_RT 82
#define DHCP6_OPTION_CLIENT_ARCH_TYPE 61
#define DHCP6_OPTION_VENDOR_CLASS 16
#define DHCP6_OPTION_NII 62
/* DUID */
#define DUID_TYPE_LL 3
#define DUID_HW_TYPE_ENET 1
#define DUID_LL_SIZE (sizeof(struct dhcp6_option_duid_ll) + ETH_ALEN)
#define DUID_MAX_SIZE DUID_LL_SIZE /* only supports DUID-LL currently */
/* vendor-class-data to send in vendor clas option */
#define DHCP6_VCI_STRING "U-boot"
#define DHCP6_MULTICAST_ADDR "ff02::1:2" /* DHCP multicast address */
/* DHCP6 States supported */
enum dhcp6_state {
DHCP6_INIT,
DHCP6_SOLICIT,
DHCP6_REQUEST,
DHCP6_DONE,
DHCP6_FAIL,
};
/* DHCP6 Status codes */
enum dhcp6_status {
DHCP6_SUCCESS = 0,
DHCP6_UNSPEC_FAIL = 1,
DHCP6_NO_ADDRS_AVAIL = 2,
DHCP6_NO_BINDING = 3,
DHCP6_NOT_ON_LINK = 4,
DHCP6_USE_MULTICAST = 5,
DHCP6_NO_PREFIX_AVAIL = 6,
};
/* DHCP6 message header format */
struct dhcp6_hdr {
unsigned int msg_type : 8; /* message type */
unsigned int trans_id : 24; /* transaction ID */
} __packed;
/* DHCP6 option header format */
struct dhcp6_option_hdr {
__be16 option_id; /* option id */
__be16 option_len; /* Option length */
u8 option_data[0]; /* Option data */
} __packed;
/* DHCP6_OPTION_CLIENTID option (DUID-LL) */
struct dhcp6_option_duid_ll {
__be16 duid_type;
__be16 hw_type;
u8 ll_addr[0];
} __packed;
/* DHCP6_OPTION_ELAPSED_TIME option */
struct dhcp6_option_elapsed_time {
__be16 elapsed_time;
} __packed;
/* DHCP6_OPTION_IA_TA option */
struct dhcp6_option_ia_ta {
__be32 iaid;
u8 ia_ta_options[0];
} __packed;
/* DHCP6_OPTION_IA_NA option */
struct dhcp6_option_ia_na {
__be32 iaid;
__be32 t1;
__be32 t2;
u8 ia_na_options[0];
} __packed;
/* OPTION_ORO option */
struct dhcp6_option_oro {
__be16 req_option_code[0];
} __packed;
/* DHCP6_OPTION_CLIENT_ARCH_TYPE option */
struct dhcp6_option_client_arch {
__be16 arch_type[0];
} __packed;
/* vendor-class-data inside OPTION_VENDOR_CLASS option */
struct vendor_class_data {
__be16 vendor_class_len;
u8 opaque_data[0];
} __packed;
/* DHCP6_OPTION_VENDOR_CLASS option */
struct dhcp6_option_vendor_class {
__be32 enterprise_number;
struct vendor_class_data vendor_class_data[0];
} __packed;
/**
* struct dhcp6_rx_pkt_status - Structure that holds status
* from a received message
* @client_id_match: Client ID was found and matches DUID sent
* @server_id_found: Server ID was found in the message
* @server_uid_ptr: Pointer to received server ID
* @server_uid_size: Size of received server ID
* @ia_addr_found: IA addr option was found in received message
* @ia_addr_ipv6: The IPv6 address received in IA
* @ia_status_code: Status code received in the IA
* @status_code: Top-level status code received
* @preference: Preference code received
*/
struct dhcp6_rx_pkt_status {
bool client_id_match;
bool server_id_found;
uchar *server_uid_ptr;
u16 server_uid_size;
bool ia_addr_found;
struct in6_addr ia_addr_ipv6;
enum dhcp6_status ia_status_code;
enum dhcp6_status status_code;
u8 preference;
};
/**
* struct dhcp6_server_uid - Structure that holds the server UID
* received from an ADVERTISE and saved
* given the server selection criteria.
* @uid_ptr: Dynamically allocated and copied server UID
* @uid_size: Size of the server UID in uid_ptr (in bytes)
* @preference: Preference code associated with this server UID
*/
struct dhcp6_server_uid {
uchar *uid_ptr;
u16 uid_size;
u8 preference;
};
/**
* struct dhcp6_sm_params - Structure that holds DHCP6
* state machine parameters
* @curr_state: current DHCP6 state
* @next_state: next DHCP6 state
* @dhcp6_start_ms: timestamp DHCP6 start
* @dhcp6_retry_start_ms: timestamp of current TX message start
* @dhcp6_retry_ms: timestamp of last retransmission
* @retry_cnt: retry count
* @trans_id: transaction ID
* @ia_id: transmitted IA ID
* @irt_ms: Initial retransmission time (in ms)
* @mrt_ms: Maximum retransmission time (in ms)
* @mrc: Maximum retransmission count
* @mrd_ms: Maximum retransmission duration (in ms)
* @rt_ms: retransmission timeout (is ms)
* @rt_prev_ms: previous retransmission timeout
* @rx_status: Status from received message
* @server_uid: Saved Server UID for selected server
* @duid: pointer to transmitted Client DUID
*/
struct dhcp6_sm_params {
enum dhcp6_state curr_state;
enum dhcp6_state next_state;
ulong dhcp6_start_ms;
ulong dhcp6_retry_start_ms;
ulong dhcp6_retry_ms;
u32 retry_cnt;
u32 trans_id;
u32 ia_id;
int irt_ms;
int mrt_ms;
int mrc;
int mrd_ms;
int rt_ms;
int rt_prev_ms;
struct dhcp6_rx_pkt_status rx_status;
struct dhcp6_server_uid server_uid;
char duid[DUID_MAX_SIZE];
};
/* Starts a DHCPv6 4-message exchange as a DHCPv6 client. On successful exchange,
* the DHCPv6 state machine will transition from internal states:
* DHCP6_INIT->DHCP6_SOLICIT->DHCP6_REQUEST->DHCP6_DONE
*
* Transmitted SOLICIT and REQUEST packets will set/request the minimum required
* DHCPv6 options to PXE boot.
*
* After a successful exchange, the DHCPv6 assigned address will be set in net_ip6
*
* Additionally, the following will be set after receiving these options:
* DHCP6_OPTION_OPT_BOOTFILE_URL (option 59) -> net_server_ip6, net_boot_file_name
* DHCP6_OPTION_OPT_BOOTFILE_PARAM (option 60) - > pxelinux_configfile
*
* Illustration of a 4-message exchange with 2 servers (copied from
* https://www.rfc-editor.org/rfc/rfc8415):
*
* Server Server
* (not selected) Client (selected)
*
* v v v
* | | |
* | Begins initialization |
* | | |
* start of | _____________/|\_____________ |
* 4-message |/ Solicit | Solicit \|
* exchange | | |
* Determines | Determines
* configuration | configuration
* | | |
* |\ | ____________/|
* | \________ | /Advertise |
* | Advertise\ |/ |
* | \ | |
* | Collects Advertises |
* | \ | |
* | Selects configuration |
* | | |
* | _____________/|\_____________ |
* |/ Request | Request \|
* | | |
* | | Commits configuration
* | | |
* end of | | _____________/|
* 4-message | |/ Reply |
* exchange | | |
* | Initialization complete |
* | | |
*/
void dhcp6_start(void);
#endif /* __DHCP6_H__ */