3 * Add functionality DHCPv6 to l2tpns.
7 #include <netinet/icmp6.h>
8 #include <linux/rtnetlink.h>
9 #include <netinet/ip6.h>
10 #include <netinet/udp.h>
16 struct dhcp6_in_option
18 struct dhcp6_mess_hdr
*p_mess_hdr
;
19 struct dhcp6_opt_h
*p_opt_clientid
;
20 struct dhcp6_opt_h
*p_opt_serverid
;
21 struct dhcp6_opt_h
*p_opt_ia_na
;
22 struct dhcp6_opt_h
*p_opt_ia_ta
;
23 struct dhcp6_opt_h
*p_opt_ia_pd
;
24 struct dhcp6_opt_h
*p_opt_oro
;
25 struct dhcp6_opt_h
*p_opt_rapidcommit
;
28 static struct dhcp6_opt_serverid dhcp6_local_serverid
;
29 static struct dhcp6_in_option list_option
;
31 static int dhcpv6_format_dns_search_name(const char *strdns
, uint8_t *buffer
);
33 static void dhcp6_send_reply(sessionidt s
, tunnelidt t
, struct in6_addr
*ip6_src
)
35 struct ip6_hdr
*p_ip6_hdr
;
37 struct dhcp6_mess_hdr
*p_mess_hdr
;
38 struct dhcp6_opt_h
*p_opt
;
39 struct ipv6_pseudo_hdr pseudo_hdr
;
40 uint8_t b
[MAXETHER
+ 20];
43 memset(b
, 0, sizeof(b
));
44 p_ip6_hdr
= (struct ip6_hdr
*) makeppp(b
, sizeof(b
), 0, 0, s
, t
, PPPIPV6
, 0, 0, 0);
47 p_ip6_hdr
->ip6_vfc
= 0x60; // IPv6
48 p_ip6_hdr
->ip6_plen
= 0; // Length of payload (not header) (calculation below)
49 p_ip6_hdr
->ip6_nxt
= IPPROTO_UDP
; // icmp6 is next
50 p_ip6_hdr
->ip6_hlim
= 1; // Hop limit
52 inet_pton(AF_INET6
, "FE02::1:2", &p_ip6_hdr
->ip6_src
.s6_addr
);
54 memcpy(&p_ip6_hdr
->ip6_dst
.s6_addr
, ip6_src
, sizeof(p_ip6_hdr
->ip6_dst
.s6_addr
));
57 p_udp
= (struct udphdr
*) &p_ip6_hdr
[1];
58 p_udp
->source
= htons(547);
59 p_udp
->dest
= htons(546);
60 p_udp
->len
= 0; // Length udp size_udp_header + data (calculation below)
61 p_udp
->check
= 0; // checksum (calculation below with ip pseudo header)
64 p_mess_hdr
= (struct dhcp6_mess_hdr
*) &p_udp
[1];
65 if (list_option
.p_mess_hdr
->type
== DHCP6_SOLICIT
)
66 p_mess_hdr
->type
= list_option
.p_opt_rapidcommit
? DHCP6_REPLY
: DHCP6_ADVERTISE
;
68 p_mess_hdr
->type
= DHCP6_REPLY
;
70 p_mess_hdr
->trans_id
= list_option
.p_mess_hdr
->trans_id
;
72 // DHCPv6 options header
73 p_opt
= (struct dhcp6_opt_h
*) &p_mess_hdr
[1];
74 memcpy(p_opt
, &dhcp6_local_serverid
, ntohs(dhcp6_local_serverid
.opt_hdr
.len
) + sizeof(dhcp6_local_serverid
.opt_hdr
)); // ServerID
75 p_opt
= (struct dhcp6_opt_h
*) (((uint8_t *) p_opt
) + ntohs(p_opt
->len
) + sizeof(*p_opt
)); // next option
77 if (list_option
.p_opt_clientid
)
79 memcpy(p_opt
, list_option
.p_opt_clientid
, ntohs(list_option
.p_opt_clientid
->len
) + sizeof(*p_opt
)); // ClientID
80 p_opt
= (struct dhcp6_opt_h
*) (((uint8_t *) p_opt
) + ntohs(p_opt
->len
) + sizeof(*p_opt
)); // next option
83 if (list_option
.p_opt_ia_pd
&& (list_option
.p_mess_hdr
->type
!= DHCP6_INFORMATION_REQUEST
))
85 p_opt
->code
= htons(D6_OPT_IA_PD
); // D6_OPT_IA_PD
86 ((struct dhcp6_opt_ia_pd
*)p_opt
)->iaid
= ((struct dhcp6_opt_ia_pd
*)list_option
.p_opt_ia_pd
)->iaid
;
87 ((struct dhcp6_opt_ia_pd
*)p_opt
)->T1
= (config
->dhcp6_preferred_lifetime
> 0) ? htonl(config
->dhcp6_preferred_lifetime
/2) : 0xFFFFFFFF;
88 ((struct dhcp6_opt_ia_pd
*)p_opt
)->T2
= (config
->dhcp6_preferred_lifetime
> 0) ? htonl((config
->dhcp6_preferred_lifetime
*4)/5) : 0xFFFFFFFF;
90 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
)
92 p_opt
->len
= htons(sizeof(struct dhcp6_opt_ia_pd
) - sizeof(*p_opt
) + sizeof(struct dhcp6_opt_status
));
93 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_ia_pd
*)p_opt
)[1];
95 ((struct dhcp6_opt_status
*)p_opt
)->hdr
.code
= htons(D6_OPT_STATUS_CODE
);
96 ((struct dhcp6_opt_status
*)p_opt
)->hdr
.len
= htons(2);
97 ((struct dhcp6_opt_status
*)p_opt
)->code
= htons(D6_STATUS_NoBinding
);
98 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_status
*)p_opt
)[1]; // next option
102 struct dhcp6_opt_h
*p_opt_head
;
106 if (list_option
.p_mess_hdr
->type
== DHCP6_REQUEST
|| list_option
.p_opt_rapidcommit
)
108 session
[s
].dhcpv6_prefix_iaid
= ((struct dhcp6_opt_ia_pd
*)list_option
.p_opt_ia_pd
)->iaid
;
112 lenopt
= sizeof(struct dhcp6_opt_ia_pd
) - sizeof(*p_opt
);
114 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_ia_pd
*)p_opt
)[1];
116 for (r
= 0; r
< MAXROUTE6
&& session
[s
].route6
[r
].ipv6route
.s6_addr
[0] && session
[s
].route6
[r
].ipv6prefixlen
; r
++)
118 ((struct dhcp6_opt_ia_prefix
*)p_opt
)->hdr
.code
= htons(D6_OPT_IAPREFIX
);
119 ((struct dhcp6_opt_ia_prefix
*)p_opt
)->hdr
.len
= htons(sizeof(struct dhcp6_opt_ia_prefix
) - sizeof(*p_opt
));
120 ((struct dhcp6_opt_ia_prefix
*)p_opt
)->pref_lifetime
= (config
->dhcp6_preferred_lifetime
> 0) ? htonl(config
->dhcp6_preferred_lifetime
) : 0xFFFFFFFF;
121 ((struct dhcp6_opt_ia_prefix
*)p_opt
)->valid_lifetime
= (config
->dhcp6_valid_lifetime
> 0) ? htonl(config
->dhcp6_valid_lifetime
) : 0xFFFFFFFF;
122 ((struct dhcp6_opt_ia_prefix
*)p_opt
)->prefix_len
= session
[s
].route6
[r
].ipv6prefixlen
;
123 ((struct dhcp6_opt_ia_prefix
*)p_opt
)->prefix
= session
[s
].route6
[r
].ipv6route
;
125 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_ia_prefix
*)p_opt
)[1]; // next option
126 lenopt
+= sizeof(struct dhcp6_opt_ia_prefix
);
128 p_opt_head
->len
= htons(lenopt
);
132 if (list_option
.p_opt_ia_na
&& (list_option
.p_mess_hdr
->type
!= DHCP6_INFORMATION_REQUEST
))
134 p_opt
->code
= htons(D6_OPT_IA_NA
); // D6_OPT_IA_NA
135 ((struct dhcp6_opt_ia_na
*)p_opt
)->iaid
= ((struct dhcp6_opt_ia_na
*)list_option
.p_opt_ia_na
)->iaid
;
136 ((struct dhcp6_opt_ia_na
*)p_opt
)->T1
= (config
->dhcp6_preferred_lifetime
> 0) ? htonl(config
->dhcp6_preferred_lifetime
/2) : 0xFFFFFFFF;
137 ((struct dhcp6_opt_ia_na
*)p_opt
)->T2
= (config
->dhcp6_preferred_lifetime
> 0) ? htonl((config
->dhcp6_preferred_lifetime
*4)/5) : 0xFFFFFFFF;
139 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
)
141 p_opt
->len
= htons(sizeof(struct dhcp6_opt_ia_na
) - sizeof(*p_opt
) + sizeof(struct dhcp6_opt_status
));
142 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_ia_na
*)p_opt
)[1];
144 ((struct dhcp6_opt_status
*)p_opt
)->hdr
.code
= htons(D6_OPT_STATUS_CODE
);
145 ((struct dhcp6_opt_status
*)p_opt
)->hdr
.len
= htons(2);
146 ((struct dhcp6_opt_status
*)p_opt
)->code
= htons(D6_STATUS_NoBinding
);
147 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_status
*)p_opt
)[1]; // next option
153 if (list_option
.p_mess_hdr
->type
== DHCP6_REQUEST
|| list_option
.p_opt_rapidcommit
)
155 session
[s
].dhcpv6_iana_iaid
= ((struct dhcp6_opt_ia_na
*)list_option
.p_opt_ia_na
)->iaid
;
158 p_opt
->len
= htons(sizeof(struct dhcp6_opt_ia_na
) - sizeof(*p_opt
) + sizeof(struct dhcp6_opt_ia_addr
));
159 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_ia_na
*)p_opt
)[1];
161 ((struct dhcp6_opt_ia_addr
*)p_opt
)->hdr
.code
= htons(D6_OPT_IAADDR
);
162 ((struct dhcp6_opt_ia_addr
*)p_opt
)->hdr
.len
= htons(sizeof(struct dhcp6_opt_ia_addr
) - sizeof(*p_opt
));
164 if (session
[s
].ipv6address
.s6_addr
[0])
166 memcpy(&((struct dhcp6_opt_ia_addr
*)p_opt
)->addr
, &session
[s
].ipv6address
, 16); // copy ipv6 prefix
170 memcpy(&((struct dhcp6_opt_ia_addr
*)p_opt
)->addr
, &config
->ipv6_prefix
, 8); // copy prefix 64
171 addr_ipv4
= htonl(session
[s
].ip
);
172 memcpy(&((struct dhcp6_opt_ia_addr
*)p_opt
)->addr
.s6_addr
[8], &addr_ipv4
, 4); // copy ipv4
175 ((struct dhcp6_opt_ia_addr
*)p_opt
)->pref_lifetime
= (config
->dhcp6_preferred_lifetime
> 0) ? htonl(config
->dhcp6_preferred_lifetime
) : 0xFFFFFFFF;
176 ((struct dhcp6_opt_ia_addr
*)p_opt
)->valid_lifetime
= (config
->dhcp6_valid_lifetime
> 0) ? htonl(config
->dhcp6_valid_lifetime
) : 0xFFFFFFFF;
178 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_ia_addr
*)p_opt
)[1]; // next option
182 if (list_option
.p_opt_ia_ta
&& (list_option
.p_mess_hdr
->type
!= DHCP6_INFORMATION_REQUEST
))
184 p_opt
->code
= htons(D6_OPT_IA_TA
); // D6_OPT_IA_TA
185 p_opt
->len
= htons(sizeof(struct dhcp6_opt_ia_ta
) - sizeof(*p_opt
) + sizeof(struct dhcp6_opt_status
));
186 ((struct dhcp6_opt_ia_ta
*)p_opt
)->iaid
= ((struct dhcp6_opt_ia_ta
*)list_option
.p_opt_ia_ta
)->iaid
;
187 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_ia_ta
*)p_opt
)[1];
188 ((struct dhcp6_opt_status
*)p_opt
)->hdr
.code
= htons(D6_OPT_STATUS_CODE
);
189 ((struct dhcp6_opt_status
*)p_opt
)->hdr
.len
= htons(2);
190 ((struct dhcp6_opt_status
*)p_opt
)->code
= htons(D6_STATUS_UnspecFail
);
191 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_status
*)p_opt
)[1]; // next option
194 if (list_option
.p_opt_oro
)
198 struct in6_addr
*ptr_in6_addr
;
200 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
++)
202 if (ntohs(*ptrw
) == D6_OPT_DNS_SERVERS
)
204 if (config
->default_ipv6_dns1
.s6_addr
[0])
206 p_opt
->code
= htons(D6_OPT_DNS_SERVERS
); // D6_OPT_DNS_SERVERS
207 p_opt
->len
= htons(sizeof(*ptr_in6_addr
));
208 ptr_in6_addr
= (struct in6_addr
*) &p_opt
[1];
209 memcpy(ptr_in6_addr
, &config
->default_ipv6_dns1
, sizeof(*ptr_in6_addr
));
211 if (config
->default_ipv6_dns2
.s6_addr
[0])
213 p_opt
->len
= htons(2*sizeof(*ptr_in6_addr
));
214 ptr_in6_addr
= &ptr_in6_addr
[1];
215 memcpy(ptr_in6_addr
, &config
->default_ipv6_dns2
, sizeof(*ptr_in6_addr
));
218 p_opt
= (struct dhcp6_opt_h
*) &ptr_in6_addr
[1]; // next option
222 if (ntohs(*ptrw
) == D6_OPT_DOMAIN_LIST
)
224 if (*config
->default_ipv6_domain_list
)
227 int len
= dhcpv6_format_dns_search_name(config
->default_ipv6_domain_list
, buffer
);
231 p_opt
->code
= htons(D6_OPT_DOMAIN_LIST
); // D6_OPT_DOMAIN_LIST
232 p_opt
->len
= htons(len
);
233 memcpy((char *)&p_opt
[1], buffer
, len
);
235 p_opt
= (struct dhcp6_opt_h
*) (((uint8_t *) &p_opt
[1]) + len
); // next option
242 if (list_option
.p_opt_rapidcommit
&& (list_option
.p_mess_hdr
->type
== DHCP6_SOLICIT
))
244 p_opt
->code
= htons(D6_OPT_RAPID_COMMIT
); // D6_OPT_RAPID_COMMIT
246 p_opt
= &p_opt
[1]; // next option
249 p_opt
->code
= htons(D6_OPT_PREFERENCE
); // D6_OPT_PREFERENCE
250 p_opt
->len
= htons(1);
251 ((struct dhcp6_opt_preference
*)p_opt
)->pref
= 255;
252 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_preference
*)p_opt
)[1]; // next option
254 // calculation of lenght
255 len
= ((uint8_t *) p_opt
) - ((uint8_t *) p_udp
);
256 p_ip6_hdr
->ip6_plen
= p_udp
->len
= htons(len
);
258 /* Use pseudo hearder for checksum calculation */
259 memset(&pseudo_hdr
, 0, sizeof(pseudo_hdr
));
260 memcpy(&pseudo_hdr
.src
, &p_ip6_hdr
->ip6_src
, 16);
261 memcpy(&pseudo_hdr
.dest
, &p_ip6_hdr
->ip6_dst
, 16);
262 pseudo_hdr
.ulp_length
= htonl(len
); // Lenght whitout Ipv6 header
263 pseudo_hdr
.nexthdr
= IPPROTO_UDP
;
264 // Checksum is over the udp payload plus the pseudo header
265 p_udp
->check
= ipv6_checksum(&pseudo_hdr
, (uint8_t *) p_udp
, len
);
267 // Add ipv6 header to length
268 len
+= sizeof(*p_ip6_hdr
);
269 LOG(3, s
, t
, "Send DHCPv6 message %s\n", (p_mess_hdr
->type
== DHCP6_REPLY
) ? "REPLY" : "ADVERTISE");
270 tunnelsend(b
, len
+ (((uint8_t *) p_ip6_hdr
)-b
), t
); // send it...
273 static char * get_msg_type(uint8_t type
)
291 case DHCP6_INFORMATION_REQUEST
:
292 return "Information Request";
313 void dhcpv6_process(sessionidt s
, tunnelidt t
, uint8_t *p
, uint16_t l
)
315 struct ip6_hdr
*p_ip6_hdr_in
;
316 struct dhcp6_mess_hdr
*p_mess_hdr
;
317 struct dhcp6_opt_h
*p_opt
;
321 CSTAT(dhcpv6_process
);
323 p_ip6_hdr_in
= (struct ip6_hdr
*) p
;
324 p_mess_hdr
= (struct dhcp6_mess_hdr
*) (p
+ 48);
326 LOG(3, s
, t
, "Got DHCPv6 message Type: %s(%d)\n", get_msg_type(p_mess_hdr
->type
), p_mess_hdr
->type
);
328 if (!session
[s
].route6
[0].ipv6route
.s6_addr
[0] || !session
[s
].route6
[0].ipv6prefixlen
)
331 p_opt
= (struct dhcp6_opt_h
*) &p_mess_hdr
[1];
332 p_end
= ((uint8_t *)p_ip6_hdr_in
) + ntohs(p_ip6_hdr_in
->ip6_plen
) + sizeof(*p_ip6_hdr_in
);
333 memset(&list_option
, 0, sizeof(list_option
));
334 list_option
.p_mess_hdr
= p_mess_hdr
;
335 while (((uint8_t *)p_opt
) < p_end
)
337 switch(ntohs(p_opt
->code
))
339 case D6_OPT_CLIENTID
:
340 list_option
.p_opt_clientid
= p_opt
;
341 LOG(3, s
, t
, "......Option D6_OPT_CLIENTID\n");
343 case D6_OPT_SERVERID
:
344 list_option
.p_opt_serverid
= p_opt
;
345 LOG(3, s
, t
, "......Option D6_OPT_SERVERID\n");
347 case D6_OPT_RAPID_COMMIT
:
348 list_option
.p_opt_rapidcommit
= p_opt
;
349 LOG(3, s
, t
, "......Option D6_OPT_RAPID_COMMIT\n");
352 list_option
.p_opt_ia_na
= p_opt
;
353 LOG(3, s
, t
, "......Option D6_OPT_IA_NA\n");
356 list_option
.p_opt_ia_ta
= p_opt
;
357 LOG(3, s
, t
, "......Option D6_OPT_IA_TA\n");
360 list_option
.p_opt_oro
= p_opt
;
361 LOG(3, s
, t
, "......Option D6_OPT_ORO\n");
364 list_option
.p_opt_ia_pd
= p_opt
;
365 LOG(3, s
, t
, "......Option D6_OPT_IA_PD\n");
367 case D6_OPT_ELAPSED_TIME
:
368 LOG(3, s
, t
, "......Option D6_OPT_ELAPSED_TIME\n");
372 LOG(3, s
, t
, "......DHCPv6 option: %d\n", ntohs(p_opt
->code
));
375 p_opt
= (struct dhcp6_opt_h
*)(((uint8_t *) p_opt
) + ntohs(p_opt
->len
) + sizeof(*p_opt
));
378 switch(p_mess_hdr
->type
)
382 if (!list_option
.p_opt_clientid
)
384 LOG(3, s
, t
, "DHCPv6: error no Client-ID\n");
387 else if (list_option
.p_opt_rapidcommit
)
389 if (!session
[s
].dhcpv6_client_id
.opt_hdr
.len
)
391 len
= ntohs(list_option
.p_opt_clientid
->len
);
393 if ((len
> 0) && (len
<= sizeof(struct dhcp6_duid
)))
395 memcpy(&session
[s
].dhcpv6_client_id
, list_option
.p_opt_clientid
, sizeof(struct dhcp6_opt_h
) + len
);
399 LOG(3, s
, t
, "DHCPv6: Error malformed Client-ID option\n");
403 else if (session
[s
].dhcpv6_client_id
.opt_hdr
.len
!= list_option
.p_opt_clientid
->len
||
404 memcmp(&session
[s
].dhcpv6_client_id
, list_option
.p_opt_clientid
, sizeof(struct dhcp6_opt_h
) + ntohs(list_option
.p_opt_clientid
->len
)))
406 LOG(3, s
, t
, "DHCPv6: Error unmatched Client-ID option\n");
411 if (list_option
.p_opt_serverid
)
413 LOG(3, s
, t
, "DHCPv6: Error unexpected Server-ID option on Solicit\n");
417 dhcp6_send_reply(s
, t
, &p_ip6_hdr_in
->ip6_src
);
423 if (!list_option
.p_opt_clientid
)
425 LOG(3, s
, t
, "DHCPv6: error no Client-ID\n");
429 if (!list_option
.p_opt_serverid
)
431 LOG(3, s
, t
, "DHCPv6: error no Server-ID\n");
434 else if (dhcp6_local_serverid
.opt_hdr
.len
!= list_option
.p_opt_serverid
->len
||
435 memcmp(&dhcp6_local_serverid
, list_option
.p_opt_serverid
, sizeof(struct dhcp6_opt_h
) + ntohs(list_option
.p_opt_serverid
->len
)))
437 LOG(3, s
, t
, "DHCPv6: Error unmatched Server-ID option\n");
441 if (!session
[s
].dhcpv6_client_id
.opt_hdr
.len
)
443 len
= ntohs(list_option
.p_opt_clientid
->len
);
445 if ((len
> 0) && (len
<= sizeof(struct dhcp6_duid
)))
447 memcpy(&session
[s
].dhcpv6_client_id
, list_option
.p_opt_clientid
, sizeof(struct dhcp6_opt_h
) + len
);
451 LOG(3, s
, t
, "DHCPv6: Error malformed Client-ID option\n");
455 else if ( session
[s
].dhcpv6_client_id
.opt_hdr
.len
!= list_option
.p_opt_clientid
->len
||
456 memcmp(&session
[s
].dhcpv6_client_id
, list_option
.p_opt_clientid
, sizeof(struct dhcp6_opt_h
) + ntohs(list_option
.p_opt_clientid
->len
)))
458 LOG(3, s
, t
, "DHCPv6: Error unmatched Client-ID option\n");
462 dhcp6_send_reply(s
, t
, &p_ip6_hdr_in
->ip6_src
);
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
));