Sean Edmond | e8c4383 | 2023-04-11 10:48:46 -0700 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0+ */ |
| 2 | /* |
| 3 | * Copyright (C) Microsoft Corporation |
| 4 | * Author: Sean Edmond <seanedmond@microsoft.com> |
| 5 | * |
| 6 | */ |
| 7 | |
| 8 | #ifndef __DHCP6_H__ |
| 9 | #define __DHCP6_H__ |
| 10 | |
| 11 | /* Message types */ |
| 12 | #define DHCP6_MSG_SOLICIT 1 |
| 13 | #define DHCP6_MSG_ADVERTISE 2 |
| 14 | #define DHCP6_MSG_REQUEST 3 |
| 15 | #define DHCP6_MSG_REPLY 7 |
| 16 | |
| 17 | /* Option Codes */ |
| 18 | #define DHCP6_OPTION_CLIENTID 1 |
| 19 | #define DHCP6_OPTION_SERVERID 2 |
| 20 | #define DHCP6_OPTION_IA_NA 3 |
| 21 | #define DHCP6_OPTION_IA_TA 4 |
| 22 | #define DHCP6_OPTION_IAADDR 5 |
| 23 | #define DHCP6_OPTION_ORO 6 |
| 24 | #define DHCP6_OPTION_PREFERENCE 7 |
| 25 | #define DHCP6_OPTION_ELAPSED_TIME 8 |
| 26 | #define DHCP6_OPTION_STATUS_CODE 13 |
| 27 | #define DHCP6_OPTION_OPT_BOOTFILE_URL 59 |
| 28 | #define DHCP6_OPTION_OPT_BOOTFILE_PARAM 60 |
| 29 | #define DHCP6_OPTION_SOL_MAX_RT 82 |
| 30 | #define DHCP6_OPTION_CLIENT_ARCH_TYPE 61 |
| 31 | #define DHCP6_OPTION_VENDOR_CLASS 16 |
| 32 | #define DHCP6_OPTION_NII 62 |
| 33 | |
| 34 | /* DUID */ |
| 35 | #define DUID_TYPE_LL 3 |
| 36 | #define DUID_HW_TYPE_ENET 1 |
| 37 | #define DUID_LL_SIZE (sizeof(struct dhcp6_option_duid_ll) + ETH_ALEN) |
| 38 | #define DUID_MAX_SIZE DUID_LL_SIZE /* only supports DUID-LL currently */ |
| 39 | |
| 40 | /* vendor-class-data to send in vendor clas option */ |
Sean Edmond | 397d97b | 2023-05-18 12:35:41 -0700 | [diff] [blame] | 41 | #define DHCP6_VCI_STRING "U-Boot" |
Sean Edmond | e8c4383 | 2023-04-11 10:48:46 -0700 | [diff] [blame] | 42 | |
| 43 | #define DHCP6_MULTICAST_ADDR "ff02::1:2" /* DHCP multicast address */ |
| 44 | |
| 45 | /* DHCP6 States supported */ |
| 46 | enum dhcp6_state { |
| 47 | DHCP6_INIT, |
| 48 | DHCP6_SOLICIT, |
| 49 | DHCP6_REQUEST, |
| 50 | DHCP6_DONE, |
| 51 | DHCP6_FAIL, |
| 52 | }; |
| 53 | |
| 54 | /* DHCP6 Status codes */ |
| 55 | enum dhcp6_status { |
| 56 | DHCP6_SUCCESS = 0, |
| 57 | DHCP6_UNSPEC_FAIL = 1, |
| 58 | DHCP6_NO_ADDRS_AVAIL = 2, |
| 59 | DHCP6_NO_BINDING = 3, |
| 60 | DHCP6_NOT_ON_LINK = 4, |
| 61 | DHCP6_USE_MULTICAST = 5, |
| 62 | DHCP6_NO_PREFIX_AVAIL = 6, |
| 63 | }; |
| 64 | |
| 65 | /* DHCP6 message header format */ |
| 66 | struct dhcp6_hdr { |
| 67 | unsigned int msg_type : 8; /* message type */ |
| 68 | unsigned int trans_id : 24; /* transaction ID */ |
| 69 | } __packed; |
| 70 | |
| 71 | /* DHCP6 option header format */ |
| 72 | struct dhcp6_option_hdr { |
| 73 | __be16 option_id; /* option id */ |
| 74 | __be16 option_len; /* Option length */ |
| 75 | u8 option_data[0]; /* Option data */ |
| 76 | } __packed; |
| 77 | |
| 78 | /* DHCP6_OPTION_CLIENTID option (DUID-LL) */ |
| 79 | struct dhcp6_option_duid_ll { |
| 80 | __be16 duid_type; |
| 81 | __be16 hw_type; |
| 82 | u8 ll_addr[0]; |
| 83 | } __packed; |
| 84 | |
| 85 | /* DHCP6_OPTION_ELAPSED_TIME option */ |
| 86 | struct dhcp6_option_elapsed_time { |
| 87 | __be16 elapsed_time; |
| 88 | } __packed; |
| 89 | |
| 90 | /* DHCP6_OPTION_IA_TA option */ |
| 91 | struct dhcp6_option_ia_ta { |
| 92 | __be32 iaid; |
| 93 | u8 ia_ta_options[0]; |
| 94 | } __packed; |
| 95 | |
| 96 | /* DHCP6_OPTION_IA_NA option */ |
| 97 | struct dhcp6_option_ia_na { |
| 98 | __be32 iaid; |
| 99 | __be32 t1; |
| 100 | __be32 t2; |
| 101 | u8 ia_na_options[0]; |
| 102 | } __packed; |
| 103 | |
| 104 | /* OPTION_ORO option */ |
| 105 | struct dhcp6_option_oro { |
| 106 | __be16 req_option_code[0]; |
| 107 | } __packed; |
| 108 | |
| 109 | /* DHCP6_OPTION_CLIENT_ARCH_TYPE option */ |
| 110 | struct dhcp6_option_client_arch { |
| 111 | __be16 arch_type[0]; |
| 112 | } __packed; |
| 113 | |
| 114 | /* vendor-class-data inside OPTION_VENDOR_CLASS option */ |
| 115 | struct vendor_class_data { |
| 116 | __be16 vendor_class_len; |
| 117 | u8 opaque_data[0]; |
| 118 | } __packed; |
| 119 | |
| 120 | /* DHCP6_OPTION_VENDOR_CLASS option */ |
| 121 | struct dhcp6_option_vendor_class { |
| 122 | __be32 enterprise_number; |
| 123 | struct vendor_class_data vendor_class_data[0]; |
| 124 | } __packed; |
| 125 | |
| 126 | /** |
| 127 | * struct dhcp6_rx_pkt_status - Structure that holds status |
| 128 | * from a received message |
| 129 | * @client_id_match: Client ID was found and matches DUID sent |
| 130 | * @server_id_found: Server ID was found in the message |
| 131 | * @server_uid_ptr: Pointer to received server ID |
| 132 | * @server_uid_size: Size of received server ID |
| 133 | * @ia_addr_found: IA addr option was found in received message |
| 134 | * @ia_addr_ipv6: The IPv6 address received in IA |
| 135 | * @ia_status_code: Status code received in the IA |
| 136 | * @status_code: Top-level status code received |
| 137 | * @preference: Preference code received |
| 138 | */ |
| 139 | struct dhcp6_rx_pkt_status { |
| 140 | bool client_id_match; |
| 141 | bool server_id_found; |
| 142 | uchar *server_uid_ptr; |
| 143 | u16 server_uid_size; |
| 144 | bool ia_addr_found; |
| 145 | struct in6_addr ia_addr_ipv6; |
| 146 | enum dhcp6_status ia_status_code; |
| 147 | enum dhcp6_status status_code; |
| 148 | u8 preference; |
| 149 | }; |
| 150 | |
| 151 | /** |
| 152 | * struct dhcp6_server_uid - Structure that holds the server UID |
| 153 | * received from an ADVERTISE and saved |
| 154 | * given the server selection criteria. |
| 155 | * @uid_ptr: Dynamically allocated and copied server UID |
| 156 | * @uid_size: Size of the server UID in uid_ptr (in bytes) |
| 157 | * @preference: Preference code associated with this server UID |
| 158 | */ |
| 159 | struct dhcp6_server_uid { |
| 160 | uchar *uid_ptr; |
| 161 | u16 uid_size; |
| 162 | u8 preference; |
| 163 | }; |
| 164 | |
| 165 | /** |
| 166 | * struct dhcp6_sm_params - Structure that holds DHCP6 |
| 167 | * state machine parameters |
| 168 | * @curr_state: current DHCP6 state |
| 169 | * @next_state: next DHCP6 state |
| 170 | * @dhcp6_start_ms: timestamp DHCP6 start |
| 171 | * @dhcp6_retry_start_ms: timestamp of current TX message start |
| 172 | * @dhcp6_retry_ms: timestamp of last retransmission |
| 173 | * @retry_cnt: retry count |
| 174 | * @trans_id: transaction ID |
| 175 | * @ia_id: transmitted IA ID |
| 176 | * @irt_ms: Initial retransmission time (in ms) |
| 177 | * @mrt_ms: Maximum retransmission time (in ms) |
| 178 | * @mrc: Maximum retransmission count |
| 179 | * @mrd_ms: Maximum retransmission duration (in ms) |
| 180 | * @rt_ms: retransmission timeout (is ms) |
| 181 | * @rt_prev_ms: previous retransmission timeout |
| 182 | * @rx_status: Status from received message |
| 183 | * @server_uid: Saved Server UID for selected server |
| 184 | * @duid: pointer to transmitted Client DUID |
| 185 | */ |
| 186 | struct dhcp6_sm_params { |
| 187 | enum dhcp6_state curr_state; |
| 188 | enum dhcp6_state next_state; |
| 189 | ulong dhcp6_start_ms; |
| 190 | ulong dhcp6_retry_start_ms; |
| 191 | ulong dhcp6_retry_ms; |
| 192 | u32 retry_cnt; |
| 193 | u32 trans_id; |
| 194 | u32 ia_id; |
| 195 | int irt_ms; |
| 196 | int mrt_ms; |
| 197 | int mrc; |
| 198 | int mrd_ms; |
| 199 | int rt_ms; |
| 200 | int rt_prev_ms; |
| 201 | struct dhcp6_rx_pkt_status rx_status; |
| 202 | struct dhcp6_server_uid server_uid; |
| 203 | char duid[DUID_MAX_SIZE]; |
| 204 | }; |
| 205 | |
| 206 | /* Starts a DHCPv6 4-message exchange as a DHCPv6 client. On successful exchange, |
| 207 | * the DHCPv6 state machine will transition from internal states: |
| 208 | * DHCP6_INIT->DHCP6_SOLICIT->DHCP6_REQUEST->DHCP6_DONE |
| 209 | * |
| 210 | * Transmitted SOLICIT and REQUEST packets will set/request the minimum required |
| 211 | * DHCPv6 options to PXE boot. |
| 212 | * |
| 213 | * After a successful exchange, the DHCPv6 assigned address will be set in net_ip6 |
| 214 | * |
| 215 | * Additionally, the following will be set after receiving these options: |
| 216 | * DHCP6_OPTION_OPT_BOOTFILE_URL (option 59) -> net_server_ip6, net_boot_file_name |
| 217 | * DHCP6_OPTION_OPT_BOOTFILE_PARAM (option 60) - > pxelinux_configfile |
| 218 | * |
| 219 | * Illustration of a 4-message exchange with 2 servers (copied from |
| 220 | * https://www.rfc-editor.org/rfc/rfc8415): |
| 221 | * |
| 222 | * Server Server |
| 223 | * (not selected) Client (selected) |
| 224 | * |
| 225 | * v v v |
| 226 | * | | | |
| 227 | * | Begins initialization | |
| 228 | * | | | |
| 229 | * start of | _____________/|\_____________ | |
| 230 | * 4-message |/ Solicit | Solicit \| |
| 231 | * exchange | | | |
| 232 | * Determines | Determines |
| 233 | * configuration | configuration |
| 234 | * | | | |
| 235 | * |\ | ____________/| |
| 236 | * | \________ | /Advertise | |
| 237 | * | Advertise\ |/ | |
| 238 | * | \ | | |
| 239 | * | Collects Advertises | |
| 240 | * | \ | | |
| 241 | * | Selects configuration | |
| 242 | * | | | |
| 243 | * | _____________/|\_____________ | |
| 244 | * |/ Request | Request \| |
| 245 | * | | | |
| 246 | * | | Commits configuration |
| 247 | * | | | |
| 248 | * end of | | _____________/| |
| 249 | * 4-message | |/ Reply | |
| 250 | * exchange | | | |
| 251 | * | Initialization complete | |
| 252 | * | | | |
| 253 | */ |
| 254 | void dhcp6_start(void); |
| 255 | |
| 256 | #endif /* __DHCP6_H__ */ |