3 * Add functionality DHCPv6 to l2tpns.
7 #include <netinet/icmp6.h>
8 #include <netinet/ip6.h>
9 #include <netinet/udp.h>
15 struct dhcp6_in_option
17 struct dhcp6_mess_hdr
*p_mess_hdr
;
18 struct dhcp6_opt_h
*p_opt_clientid
;
19 struct dhcp6_opt_h
*p_opt_serverid
;
20 struct dhcp6_opt_h
*p_opt_ia_na
;
21 struct dhcp6_opt_h
*p_opt_ia_ta
;
22 struct dhcp6_opt_h
*p_opt_ia_pd
;
23 struct dhcp6_opt_h
*p_opt_oro
;
24 struct dhcp6_opt_h
*p_opt_rapidcommit
;
27 static struct dhcp6_opt_serverid dhcp6_local_serverid
;
28 static struct dhcp6_in_option list_option
;
30 static int dhcpv6_format_dns_search_name(const char *strdns
, uint8_t *buffer
);
32 static void dhcp6_send_reply(sessionidt s
, tunnelidt t
, struct in6_addr
*ip6_src
)
34 struct ip6_hdr
*p_ip6_hdr
;
36 struct dhcp6_mess_hdr
*p_mess_hdr
;
37 struct dhcp6_opt_h
*p_opt
;
38 struct ipv6_pseudo_hdr pseudo_hdr
;
39 uint8_t b
[MAXETHER
+ 20];
42 memset(b
, 0, sizeof(b
));
43 p_ip6_hdr
= (struct ip6_hdr
*) makeppp(b
, sizeof(b
), 0, 0, s
, t
, PPPIPV6
, 0, 0, 0);
46 p_ip6_hdr
->ip6_vfc
= 0x60; // IPv6
47 p_ip6_hdr
->ip6_plen
= 0; // Length of payload (not header) (calculation below)
48 p_ip6_hdr
->ip6_nxt
= IPPROTO_UDP
; // icmp6 is next
49 p_ip6_hdr
->ip6_hlim
= 1; // Hop limit
51 inet_pton(AF_INET6
, "FE02::1:2", &p_ip6_hdr
->ip6_src
.s6_addr
);
53 memcpy(&p_ip6_hdr
->ip6_dst
.s6_addr
, ip6_src
, sizeof(p_ip6_hdr
->ip6_dst
.s6_addr
));
56 p_udp
= (struct udphdr
*) &p_ip6_hdr
[1];
57 p_udp
->source
= htons(547);
58 p_udp
->dest
= htons(546);
59 p_udp
->len
= 0; // Length udp size_udp_header + data (calculation below)
60 p_udp
->check
= 0; // checksum (calculation below with ip pseudo header)
63 p_mess_hdr
= (struct dhcp6_mess_hdr
*) &p_udp
[1];
64 if (list_option
.p_mess_hdr
->type
== DHCP6_SOLICIT
)
65 p_mess_hdr
->type
= list_option
.p_opt_rapidcommit
? DHCP6_REPLY
: DHCP6_ADVERTISE
;
67 p_mess_hdr
->type
= DHCP6_REPLY
;
69 p_mess_hdr
->trans_id
= list_option
.p_mess_hdr
->trans_id
;
71 // DHCPv6 options header
72 p_opt
= (struct dhcp6_opt_h
*) &p_mess_hdr
[1];
73 memcpy(p_opt
, &dhcp6_local_serverid
, ntohs(dhcp6_local_serverid
.opt_hdr
.len
) + sizeof(dhcp6_local_serverid
.opt_hdr
)); // ServerID
74 p_opt
= (struct dhcp6_opt_h
*) (((uint8_t *) p_opt
) + ntohs(p_opt
->len
) + sizeof(*p_opt
)); // next option
76 if (list_option
.p_opt_clientid
)
78 memcpy(p_opt
, list_option
.p_opt_clientid
, ntohs(list_option
.p_opt_clientid
->len
) + sizeof(*p_opt
)); // ClientID
79 p_opt
= (struct dhcp6_opt_h
*) (((uint8_t *) p_opt
) + ntohs(p_opt
->len
) + sizeof(*p_opt
)); // next option
82 if (list_option
.p_opt_ia_pd
&& (list_option
.p_mess_hdr
->type
!= DHCP6_INFORMATION_REQUEST
))
84 p_opt
->code
= htons(D6_OPT_IA_PD
); // D6_OPT_IA_PD
85 ((struct dhcp6_opt_ia_pd
*)p_opt
)->iaid
= ((struct dhcp6_opt_ia_pd
*)list_option
.p_opt_ia_pd
)->iaid
;
86 ((struct dhcp6_opt_ia_pd
*)p_opt
)->T1
= (config
->dhcp6_preferred_lifetime
> 0) ? htonl(config
->dhcp6_preferred_lifetime
/2) : 0xFFFFFFFF;
87 ((struct dhcp6_opt_ia_pd
*)p_opt
)->T2
= (config
->dhcp6_preferred_lifetime
> 0) ? htonl((config
->dhcp6_preferred_lifetime
*4)/5) : 0xFFFFFFFF;
89 if ((list_option
.p_mess_hdr
->type
== DHCP6_RENEW
) && session
[s
].dhcpv6_prefix_iaid
!= ((struct dhcp6_opt_ia_pd
*)list_option
.p_opt_ia_pd
)->iaid
)
91 p_opt
->len
= htons(sizeof(struct dhcp6_opt_ia_pd
) - sizeof(*p_opt
) + sizeof(struct dhcp6_opt_status
));
92 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_ia_pd
*)p_opt
)[1];
94 ((struct dhcp6_opt_status
*)p_opt
)->hdr
.code
= htons(D6_OPT_STATUS_CODE
);
95 ((struct dhcp6_opt_status
*)p_opt
)->hdr
.len
= htons(2);
96 ((struct dhcp6_opt_status
*)p_opt
)->code
= htons(D6_STATUS_NoBinding
);
97 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_status
*)p_opt
)[1]; // next option
101 struct dhcp6_opt_h
*p_opt_head
;
105 if (list_option
.p_mess_hdr
->type
== DHCP6_REQUEST
|| list_option
.p_opt_rapidcommit
)
107 session
[s
].dhcpv6_prefix_iaid
= ((struct dhcp6_opt_ia_pd
*)list_option
.p_opt_ia_pd
)->iaid
;
111 lenopt
= sizeof(struct dhcp6_opt_ia_pd
) - sizeof(*p_opt
);
113 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_ia_pd
*)p_opt
)[1];
115 for (r
= 0; r
< MAXROUTE6
&& session
[s
].route6
[r
].ipv6route
.s6_addr
[0] && session
[s
].route6
[r
].ipv6prefixlen
; r
++)
117 ((struct dhcp6_opt_ia_prefix
*)p_opt
)->hdr
.code
= htons(D6_OPT_IAPREFIX
);
118 ((struct dhcp6_opt_ia_prefix
*)p_opt
)->hdr
.len
= htons(sizeof(struct dhcp6_opt_ia_prefix
) - sizeof(*p_opt
));
119 ((struct dhcp6_opt_ia_prefix
*)p_opt
)->pref_lifetime
= (config
->dhcp6_preferred_lifetime
> 0) ? htonl(config
->dhcp6_preferred_lifetime
) : 0xFFFFFFFF;
120 ((struct dhcp6_opt_ia_prefix
*)p_opt
)->valid_lifetime
= (config
->dhcp6_valid_lifetime
> 0) ? htonl(config
->dhcp6_valid_lifetime
) : 0xFFFFFFFF;
121 ((struct dhcp6_opt_ia_prefix
*)p_opt
)->prefix_len
= session
[s
].route6
[r
].ipv6prefixlen
;
122 ((struct dhcp6_opt_ia_prefix
*)p_opt
)->prefix
= session
[s
].route6
[r
].ipv6route
;
124 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_ia_prefix
*)p_opt
)[1]; // next option
125 lenopt
+= sizeof(struct dhcp6_opt_ia_prefix
);
127 p_opt_head
->len
= htons(lenopt
);
131 if (list_option
.p_opt_ia_na
&& (list_option
.p_mess_hdr
->type
!= DHCP6_INFORMATION_REQUEST
))
133 p_opt
->code
= htons(D6_OPT_IA_NA
); // D6_OPT_IA_NA
134 ((struct dhcp6_opt_ia_na
*)p_opt
)->iaid
= ((struct dhcp6_opt_ia_na
*)list_option
.p_opt_ia_na
)->iaid
;
135 ((struct dhcp6_opt_ia_na
*)p_opt
)->T1
= (config
->dhcp6_preferred_lifetime
> 0) ? htonl(config
->dhcp6_preferred_lifetime
/2) : 0xFFFFFFFF;
136 ((struct dhcp6_opt_ia_na
*)p_opt
)->T2
= (config
->dhcp6_preferred_lifetime
> 0) ? htonl((config
->dhcp6_preferred_lifetime
*4)/5) : 0xFFFFFFFF;
138 if ((list_option
.p_mess_hdr
->type
== DHCP6_RENEW
) && session
[s
].dhcpv6_iana_iaid
!= ((struct dhcp6_opt_ia_na
*)list_option
.p_opt_ia_na
)->iaid
)
140 p_opt
->len
= htons(sizeof(struct dhcp6_opt_ia_na
) - sizeof(*p_opt
) + sizeof(struct dhcp6_opt_status
));
141 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_ia_na
*)p_opt
)[1];
143 ((struct dhcp6_opt_status
*)p_opt
)->hdr
.code
= htons(D6_OPT_STATUS_CODE
);
144 ((struct dhcp6_opt_status
*)p_opt
)->hdr
.len
= htons(2);
145 ((struct dhcp6_opt_status
*)p_opt
)->code
= htons(D6_STATUS_NoBinding
);
146 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_status
*)p_opt
)[1]; // next option
152 if (list_option
.p_mess_hdr
->type
== DHCP6_REQUEST
|| list_option
.p_opt_rapidcommit
)
154 session
[s
].dhcpv6_iana_iaid
= ((struct dhcp6_opt_ia_na
*)list_option
.p_opt_ia_na
)->iaid
;
157 p_opt
->len
= htons(sizeof(struct dhcp6_opt_ia_na
) - sizeof(*p_opt
) + sizeof(struct dhcp6_opt_ia_addr
));
158 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_ia_na
*)p_opt
)[1];
160 ((struct dhcp6_opt_ia_addr
*)p_opt
)->hdr
.code
= htons(D6_OPT_IAADDR
);
161 ((struct dhcp6_opt_ia_addr
*)p_opt
)->hdr
.len
= htons(sizeof(struct dhcp6_opt_ia_addr
) - sizeof(*p_opt
));
163 if (session
[s
].ipv6address
.s6_addr
[0])
165 memcpy(&((struct dhcp6_opt_ia_addr
*)p_opt
)->addr
, &session
[s
].ipv6address
, 16); // copy ipv6 prefix
169 memcpy(&((struct dhcp6_opt_ia_addr
*)p_opt
)->addr
, &config
->ipv6_prefix
, 8); // copy prefix 64
170 addr_ipv4
= htonl(session
[s
].ip
);
171 memcpy(&((struct dhcp6_opt_ia_addr
*)p_opt
)->addr
.s6_addr
[8], &addr_ipv4
, 4); // copy ipv4
174 ((struct dhcp6_opt_ia_addr
*)p_opt
)->pref_lifetime
= (config
->dhcp6_preferred_lifetime
> 0) ? htonl(config
->dhcp6_preferred_lifetime
) : 0xFFFFFFFF;
175 ((struct dhcp6_opt_ia_addr
*)p_opt
)->valid_lifetime
= (config
->dhcp6_valid_lifetime
> 0) ? htonl(config
->dhcp6_valid_lifetime
) : 0xFFFFFFFF;
177 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_ia_addr
*)p_opt
)[1]; // next option
181 if (list_option
.p_opt_ia_ta
&& (list_option
.p_mess_hdr
->type
!= DHCP6_INFORMATION_REQUEST
))
183 p_opt
->code
= htons(D6_OPT_IA_TA
); // D6_OPT_IA_TA
184 p_opt
->len
= htons(sizeof(struct dhcp6_opt_ia_ta
) - sizeof(*p_opt
) + sizeof(struct dhcp6_opt_status
));
185 ((struct dhcp6_opt_ia_ta
*)p_opt
)->iaid
= ((struct dhcp6_opt_ia_ta
*)list_option
.p_opt_ia_ta
)->iaid
;
186 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_ia_ta
*)p_opt
)[1];
187 ((struct dhcp6_opt_status
*)p_opt
)->hdr
.code
= htons(D6_OPT_STATUS_CODE
);
188 ((struct dhcp6_opt_status
*)p_opt
)->hdr
.len
= htons(2);
189 ((struct dhcp6_opt_status
*)p_opt
)->code
= htons(D6_STATUS_UnspecFail
);
190 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_status
*)p_opt
)[1]; // next option
193 if (list_option
.p_opt_oro
)
197 struct in6_addr
*ptr_in6_addr
;
199 for (countopt
= ntohs(list_option
.p_opt_oro
->len
)/2, ptrw
= (uint16_t *)((struct dhcp6_opt_oro
*)list_option
.p_opt_oro
)->opt_demand
; countopt
; countopt
--, ptrw
++)
201 if (ntohs(*ptrw
) == D6_OPT_DNS_SERVERS
)
203 if (config
->default_ipv6_dns1
.s6_addr
[0])
205 p_opt
->code
= htons(D6_OPT_DNS_SERVERS
); // D6_OPT_DNS_SERVERS
206 p_opt
->len
= htons(sizeof(*ptr_in6_addr
));
207 ptr_in6_addr
= (struct in6_addr
*) &p_opt
[1];
208 memcpy(ptr_in6_addr
, &config
->default_ipv6_dns1
, sizeof(*ptr_in6_addr
));
210 if (config
->default_ipv6_dns2
.s6_addr
[0])
212 p_opt
->len
= htons(2*sizeof(*ptr_in6_addr
));
213 ptr_in6_addr
= &ptr_in6_addr
[1];
214 memcpy(ptr_in6_addr
, &config
->default_ipv6_dns2
, sizeof(*ptr_in6_addr
));
217 p_opt
= (struct dhcp6_opt_h
*) &ptr_in6_addr
[1]; // next option
221 if (ntohs(*ptrw
) == D6_OPT_DOMAIN_LIST
)
223 if (*config
->default_ipv6_domain_list
)
226 int len
= dhcpv6_format_dns_search_name(config
->default_ipv6_domain_list
, buffer
);
230 p_opt
->code
= htons(D6_OPT_DOMAIN_LIST
); // D6_OPT_DOMAIN_LIST
231 p_opt
->len
= htons(len
);
232 memcpy((char *)&p_opt
[1], buffer
, len
);
234 p_opt
= (struct dhcp6_opt_h
*) (((uint8_t *) &p_opt
[1]) + len
); // next option
241 if (list_option
.p_opt_rapidcommit
&& (list_option
.p_mess_hdr
->type
== DHCP6_SOLICIT
))
243 p_opt
->code
= htons(D6_OPT_RAPID_COMMIT
); // D6_OPT_RAPID_COMMIT
245 p_opt
= &p_opt
[1]; // next option
248 p_opt
->code
= htons(D6_OPT_PREFERENCE
); // D6_OPT_PREFERENCE
249 p_opt
->len
= htons(1);
250 ((struct dhcp6_opt_preference
*)p_opt
)->pref
= 255;
251 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_preference
*)p_opt
)[1]; // next option
253 // calculation of lenght
254 len
= ((uint8_t *) p_opt
) - ((uint8_t *) p_udp
);
255 p_ip6_hdr
->ip6_plen
= p_udp
->len
= htons(len
);
257 /* Use pseudo hearder for checksum calculation */
258 memset(&pseudo_hdr
, 0, sizeof(pseudo_hdr
));
259 memcpy(&pseudo_hdr
.src
, &p_ip6_hdr
->ip6_src
, 16);
260 memcpy(&pseudo_hdr
.dest
, &p_ip6_hdr
->ip6_dst
, 16);
261 pseudo_hdr
.ulp_length
= htonl(len
); // Lenght whitout Ipv6 header
262 pseudo_hdr
.nexthdr
= IPPROTO_UDP
;
263 // Checksum is over the udp payload plus the pseudo header
264 p_udp
->check
= ipv6_checksum(&pseudo_hdr
, (uint8_t *) p_udp
, len
);
266 // Add ipv6 header to length
267 len
+= sizeof(*p_ip6_hdr
);
268 LOG(3, s
, t
, "Send DHCPv6 message %s\n", (p_mess_hdr
->type
== DHCP6_REPLY
) ? "REPLY" : "ADVERTISE");
269 tunnelsend(b
, len
+ (((uint8_t *) p_ip6_hdr
)-b
), t
); // send it...
272 static char * get_msg_type(uint8_t type
)
290 case DHCP6_INFORMATION_REQUEST
:
291 return "Information Request";
312 void dhcpv6_process(sessionidt s
, tunnelidt t
, uint8_t *p
, uint16_t l
)
314 struct ip6_hdr
*p_ip6_hdr_in
;
315 struct dhcp6_mess_hdr
*p_mess_hdr
;
316 struct dhcp6_opt_h
*p_opt
;
320 CSTAT(dhcpv6_process
);
322 p_ip6_hdr_in
= (struct ip6_hdr
*) p
;
323 p_mess_hdr
= (struct dhcp6_mess_hdr
*) (p
+ 48);
325 LOG(3, s
, t
, "Got DHCPv6 message Type: %s(%d)\n", get_msg_type(p_mess_hdr
->type
), p_mess_hdr
->type
);
327 if (!session
[s
].route6
[0].ipv6route
.s6_addr
[0] || !session
[s
].route6
[0].ipv6prefixlen
)
330 p_opt
= (struct dhcp6_opt_h
*) &p_mess_hdr
[1];
331 p_end
= ((uint8_t *)p_ip6_hdr_in
) + ntohs(p_ip6_hdr_in
->ip6_plen
) + sizeof(*p_ip6_hdr_in
);
332 memset(&list_option
, 0, sizeof(list_option
));
333 list_option
.p_mess_hdr
= p_mess_hdr
;
334 while (((uint8_t *)p_opt
) < p_end
)
336 switch(ntohs(p_opt
->code
))
338 case D6_OPT_CLIENTID
:
339 list_option
.p_opt_clientid
= p_opt
;
340 LOG(3, s
, t
, "......Option D6_OPT_CLIENTID\n");
342 case D6_OPT_SERVERID
:
343 list_option
.p_opt_serverid
= p_opt
;
344 LOG(3, s
, t
, "......Option D6_OPT_SERVERID\n");
346 case D6_OPT_RAPID_COMMIT
:
347 list_option
.p_opt_rapidcommit
= p_opt
;
348 LOG(3, s
, t
, "......Option D6_OPT_RAPID_COMMIT\n");
351 list_option
.p_opt_ia_na
= p_opt
;
352 LOG(3, s
, t
, "......Option D6_OPT_IA_NA\n");
355 list_option
.p_opt_ia_ta
= p_opt
;
356 LOG(3, s
, t
, "......Option D6_OPT_IA_TA\n");
359 list_option
.p_opt_oro
= p_opt
;
360 LOG(3, s
, t
, "......Option D6_OPT_ORO\n");
363 list_option
.p_opt_ia_pd
= p_opt
;
364 LOG(3, s
, t
, "......Option D6_OPT_IA_PD\n");
366 case D6_OPT_ELAPSED_TIME
:
367 LOG(3, s
, t
, "......Option D6_OPT_ELAPSED_TIME\n");
371 LOG(3, s
, t
, "......DHCPv6 option: %d\n", ntohs(p_opt
->code
));
374 p_opt
= (struct dhcp6_opt_h
*)(((uint8_t *) p_opt
) + ntohs(p_opt
->len
) + sizeof(*p_opt
));
377 switch(p_mess_hdr
->type
)
381 if (!list_option
.p_opt_clientid
)
383 LOG(3, s
, t
, "DHCPv6: error no Client-ID\n");
386 else if (list_option
.p_opt_rapidcommit
)
388 if (!session
[s
].dhcpv6_client_id
.opt_hdr
.len
)
390 len
= ntohs(list_option
.p_opt_clientid
->len
);
392 if ((len
> 0) && (len
<= sizeof(struct dhcp6_duid
)))
394 memcpy(&session
[s
].dhcpv6_client_id
, list_option
.p_opt_clientid
, sizeof(struct dhcp6_opt_h
) + len
);
398 LOG(3, s
, t
, "DHCPv6: Error malformed Client-ID option\n");
402 else if (session
[s
].dhcpv6_client_id
.opt_hdr
.len
!= list_option
.p_opt_clientid
->len
||
403 memcmp(&session
[s
].dhcpv6_client_id
, list_option
.p_opt_clientid
, sizeof(struct dhcp6_opt_h
) + ntohs(list_option
.p_opt_clientid
->len
)))
405 LOG(3, s
, t
, "DHCPv6: Error unmatched Client-ID option\n");
410 if (list_option
.p_opt_serverid
)
412 LOG(3, s
, t
, "DHCPv6: Error unexpected Server-ID option on Solicit\n");
416 dhcp6_send_reply(s
, t
, &p_ip6_hdr_in
->ip6_src
);
422 if (!list_option
.p_opt_clientid
)
424 LOG(3, s
, t
, "DHCPv6: error no Client-ID\n");
428 if (!list_option
.p_opt_serverid
)
430 LOG(3, s
, t
, "DHCPv6: error no Server-ID\n");
433 else if (dhcp6_local_serverid
.opt_hdr
.len
!= list_option
.p_opt_serverid
->len
||
434 memcmp(&dhcp6_local_serverid
, list_option
.p_opt_serverid
, sizeof(struct dhcp6_opt_h
) + ntohs(list_option
.p_opt_serverid
->len
)))
436 LOG(3, s
, t
, "DHCPv6: Error unmatched Server-ID option\n");
440 if (!session
[s
].dhcpv6_client_id
.opt_hdr
.len
)
442 len
= ntohs(list_option
.p_opt_clientid
->len
);
444 if ((len
> 0) && (len
<= sizeof(struct dhcp6_duid
)))
446 memcpy(&session
[s
].dhcpv6_client_id
, list_option
.p_opt_clientid
, sizeof(struct dhcp6_opt_h
) + len
);
450 LOG(3, s
, t
, "DHCPv6: Error malformed Client-ID option\n");
454 else if ( session
[s
].dhcpv6_client_id
.opt_hdr
.len
!= list_option
.p_opt_clientid
->len
||
455 memcmp(&session
[s
].dhcpv6_client_id
, list_option
.p_opt_clientid
, sizeof(struct dhcp6_opt_h
) + ntohs(list_option
.p_opt_clientid
->len
)))
457 LOG(3, s
, t
, "DHCPv6: Error unmatched Client-ID option\n");
461 dhcp6_send_reply(s
, t
, &p_ip6_hdr_in
->ip6_src
);
462 send_ipv6_ra(s
, t
, &p_ip6_hdr_in
->ip6_src
); // send a RA
468 if (!list_option
.p_opt_clientid
)
470 LOG(3, s
, t
, "DHCPv6: error no Client-ID\n");
473 else if ( session
[s
].dhcpv6_client_id
.opt_hdr
.len
!= list_option
.p_opt_clientid
->len
||
474 memcmp(&session
[s
].dhcpv6_client_id
, list_option
.p_opt_clientid
, sizeof(struct dhcp6_opt_h
) + ntohs(list_option
.p_opt_clientid
->len
)))
476 LOG(3, s
, t
, "DHCPv6: Error unmatched Client-ID option\n");
480 if (!list_option
.p_opt_serverid
)
482 LOG(3, s
, t
, "DHCPv6: error no Server-ID\n");
485 else if (dhcp6_local_serverid
.opt_hdr
.len
!= list_option
.p_opt_serverid
->len
||
486 memcmp(&dhcp6_local_serverid
, list_option
.p_opt_serverid
, sizeof(struct dhcp6_opt_h
) + ntohs(list_option
.p_opt_serverid
->len
)))
488 LOG(3, s
, t
, "DHCPv6: Error unmatched Server-ID option\n");
492 dhcp6_send_reply(s
, t
, &p_ip6_hdr_in
->ip6_src
);
496 case DHCP6_INFORMATION_REQUEST
:
498 if (!list_option
.p_opt_clientid
)
500 LOG(3, s
, t
, "DHCPv6: error no Client-ID\n");
504 dhcp6_send_reply(s
, t
, &p_ip6_hdr_in
->ip6_src
);
530 static int dhcpv6_format_dns_search_name(const char *strdns
, uint8_t *buffer
)
532 int n
= strlen(strdns
);
535 if (strdns
[n
- 1] == '.') n
++;
539 LOG(3, 0, 0, "DHCPv6: DNS search '%s' is too long\n", strdns
);
545 ptr
= strchr(strdns
, '.');
547 if (!ptr
) ptr
= strchr(strdns
, 0);
549 if (ptr
- strdns
> 63)
551 LOG(3, 0, 0, "DHCPv6: DNS search '%s' is invalid\n", strdns
);
555 *buffer
= ptr
- strdns
;
556 memcpy(buffer
+ 1, strdns
, ptr
- strdns
);
557 buffer
+= 1 + (ptr
- strdns
);
560 if (!*ptr
|| !*strdns
)
570 void dhcpv6_init(void)
574 dhcp6_local_serverid
.opt_hdr
.code
= htons(D6_OPT_SERVERID
);
575 dhcp6_local_serverid
.opt_hdr
.len
= htons(4 + sizeof(id
));
576 dhcp6_local_serverid
.duid
.type
= htons(DUID_LL
);
577 dhcp6_local_serverid
.duid
.u
.ll
.htype
= htons(27);
579 if (config
->dhcp6_server_duid
)
580 id
= htobe32(config
->dhcp6_server_duid
);
582 id
= htobe32(0xFDFDFAFA);
584 memcpy(dhcp6_local_serverid
.duid
.u
.ll
.addr
, &id
, sizeof(id
));