]>
git.proxmox.com Git - mirror_qemu.git/blob - slirp/src/dhcpv6.c
3c8f420912fceecd4a489ee121e72b3a99e06fe3
1 /* SPDX-License-Identifier: BSD-3-Clause */
3 * SLIRP stateless DHCPv6
5 * We only support stateless DHCPv6, e.g. for network booting.
6 * See RFC 3315, RFC 3736, RFC 3646 and RFC 5970 for details.
8 * Copyright 2016 Thomas Huth, Red Hat Inc.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
18 * 2. Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials provided
21 * with the distribution.
23 * 3. Neither the name of the copyright holder nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
31 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
32 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
34 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
38 * OF THE POSSIBILITY OF SUCH DAMAGE.
44 /* DHCPv6 message types */
45 #define MSGTYPE_REPLY 7
46 #define MSGTYPE_INFO_REQUEST 11
48 /* DHCPv6 option types */
49 #define OPTION_CLIENTID 1
50 #define OPTION_IAADDR 5
52 #define OPTION_DNS_SERVERS 23
53 #define OPTION_BOOTFILE_URL 59
55 struct requested_infos
{
63 * Analyze the info request message sent by the client to see what data it
64 * provided and what it wants to have. The information is gathered in the
65 * "requested_infos" struct. Note that client_id (if provided) points into
66 * the odata region, thus the caller must keep odata valid as long as it
67 * needs to access the requested_infos struct.
69 static int dhcpv6_parse_info_request(Slirp
*slirp
, uint8_t *odata
, int olen
,
70 struct requested_infos
*ri
)
75 /* Parse one option */
76 int option
= odata
[0] << 8 | odata
[1];
77 int len
= odata
[2] << 8 | odata
[3];
80 slirp
->cb
->guest_error("Guest sent bad DHCPv6 packet!", slirp
->opaque
);
86 /* According to RFC3315, we must discard requests with IA option */
90 /* Avoid very long IDs which could cause problems later */
93 ri
->client_id
= odata
+ 4;
94 ri
->client_id_len
= len
;
96 case OPTION_ORO
: /* Option request option */
100 /* Check which options the client wants to have */
101 for (i
= 0; i
< len
; i
+= 2) {
102 req_opt
= odata
[4 + i
] << 8 | odata
[4 + i
+ 1];
104 case OPTION_DNS_SERVERS
:
107 case OPTION_BOOTFILE_URL
:
108 ri
->want_boot_url
= true;
111 DEBUG_MISC("dhcpv6: Unsupported option request %d",
117 DEBUG_MISC("dhcpv6 info req: Unsupported option %d, len=%d",
130 * Handle information request messages
132 static void dhcpv6_info_request(Slirp
*slirp
, struct sockaddr_in6
*srcsas
,
133 uint32_t xid
, uint8_t *odata
, int olen
)
135 struct requested_infos ri
= { NULL
};
136 struct sockaddr_in6 sa6
, da6
;
140 if (dhcpv6_parse_info_request(slirp
, odata
, olen
, &ri
) < 0) {
148 memset(m
->m_data
, 0, m
->m_size
);
149 m
->m_data
+= IF_MAXLINKHDR
;
150 resp
= (uint8_t *)m
->m_data
+ sizeof(struct ip6
) + sizeof(struct udphdr
);
152 /* Fill in response */
153 *resp
++ = MSGTYPE_REPLY
;
154 *resp
++ = (uint8_t)(xid
>> 16);
155 *resp
++ = (uint8_t)(xid
>> 8);
156 *resp
++ = (uint8_t)xid
;
159 *resp
++ = OPTION_CLIENTID
>> 8; /* option-code high byte */
160 *resp
++ = OPTION_CLIENTID
; /* option-code low byte */
161 *resp
++ = ri
.client_id_len
>> 8; /* option-len high byte */
162 *resp
++ = ri
.client_id_len
; /* option-len low byte */
163 memcpy(resp
, ri
.client_id
, ri
.client_id_len
);
164 resp
+= ri
.client_id_len
;
167 *resp
++ = OPTION_DNS_SERVERS
>> 8; /* option-code high byte */
168 *resp
++ = OPTION_DNS_SERVERS
; /* option-code low byte */
169 *resp
++ = 0; /* option-len high byte */
170 *resp
++ = 16; /* option-len low byte */
171 memcpy(resp
, &slirp
->vnameserver_addr6
, 16);
174 if (ri
.want_boot_url
) {
175 uint8_t *sa
= slirp
->vhost_addr6
.s6_addr
;
178 *resp
++ = OPTION_BOOTFILE_URL
>> 8; /* option-code high byte */
179 *resp
++ = OPTION_BOOTFILE_URL
; /* option-code low byte */
180 smaxlen
= (uint8_t *)m
->m_data
+ IF_MTU
- (resp
+ 2);
181 slen
= snprintf((char *)resp
+ 2, smaxlen
,
182 "tftp://[%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
183 "%02x%02x:%02x%02x:%02x%02x:%02x%02x]/%s",
184 sa
[0], sa
[1], sa
[2], sa
[3], sa
[4], sa
[5], sa
[6], sa
[7],
185 sa
[8], sa
[9], sa
[10], sa
[11], sa
[12], sa
[13], sa
[14],
186 sa
[15], slirp
->bootp_filename
);
187 slen
= MIN(slen
, smaxlen
);
188 *resp
++ = slen
>> 8; /* option-len high byte */
189 *resp
++ = slen
; /* option-len low byte */
193 sa6
.sin6_addr
= slirp
->vhost_addr6
;
194 sa6
.sin6_port
= DHCPV6_SERVER_PORT
;
195 da6
.sin6_addr
= srcsas
->sin6_addr
;
196 da6
.sin6_port
= srcsas
->sin6_port
;
197 m
->m_data
+= sizeof(struct ip6
) + sizeof(struct udphdr
);
198 m
->m_len
= resp
- (uint8_t *)m
->m_data
;
199 udp6_output(NULL
, m
, &sa6
, &da6
);
203 * Handle DHCPv6 messages sent by the client
205 void dhcpv6_input(struct sockaddr_in6
*srcsas
, struct mbuf
*m
)
207 uint8_t *data
= (uint8_t *)m
->m_data
+ sizeof(struct udphdr
);
208 int data_len
= m
->m_len
- sizeof(struct udphdr
);
215 xid
= ntohl(*(uint32_t *)data
) & 0xffffff;
218 case MSGTYPE_INFO_REQUEST
:
219 dhcpv6_info_request(m
->slirp
, srcsas
, xid
, &data
[4], data_len
- 4);
222 DEBUG_MISC("dhcpv6_input: Unsupported message type 0x%x", data
[0]);