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 if (list_option
.p_mess_hdr
->type
== DHCP6_REQUEST
|| list_option
.p_opt_rapidcommit
)
103 session
[s
].dhcpv6_prefix_iaid
= ((struct dhcp6_opt_ia_pd
*)list_option
.p_opt_ia_pd
)->iaid
;
106 p_opt
->len
= htons(sizeof(struct dhcp6_opt_ia_pd
) - sizeof(*p_opt
) + sizeof(struct dhcp6_opt_ia_prefix
));
107 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_ia_pd
*)p_opt
)[1];
109 ((struct dhcp6_opt_ia_prefix
*)p_opt
)->hdr
.code
= htons(D6_OPT_IAPREFIX
);
110 ((struct dhcp6_opt_ia_prefix
*)p_opt
)->hdr
.len
= htons(sizeof(struct dhcp6_opt_ia_prefix
) - sizeof(*p_opt
));
111 ((struct dhcp6_opt_ia_prefix
*)p_opt
)->pref_lifetime
= (config
->dhcp6_preferred_lifetime
> 0) ? htonl(config
->dhcp6_preferred_lifetime
) : 0xFFFFFFFF;
112 ((struct dhcp6_opt_ia_prefix
*)p_opt
)->valid_lifetime
= (config
->dhcp6_valid_lifetime
> 0) ? htonl(config
->dhcp6_valid_lifetime
) : 0xFFFFFFFF;
113 ((struct dhcp6_opt_ia_prefix
*)p_opt
)->prefix_len
= session
[s
].ipv6prefixlen
;
114 ((struct dhcp6_opt_ia_prefix
*)p_opt
)->prefix
= session
[s
].ipv6route
;
115 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_ia_prefix
*)p_opt
)[1]; // next option
119 if (list_option
.p_opt_ia_na
&& (list_option
.p_mess_hdr
->type
!= DHCP6_INFORMATION_REQUEST
))
121 p_opt
->code
= htons(D6_OPT_IA_NA
); // D6_OPT_IA_NA
122 ((struct dhcp6_opt_ia_na
*)p_opt
)->iaid
= ((struct dhcp6_opt_ia_na
*)list_option
.p_opt_ia_na
)->iaid
;
123 ((struct dhcp6_opt_ia_na
*)p_opt
)->T1
= (config
->dhcp6_preferred_lifetime
> 0) ? htonl(config
->dhcp6_preferred_lifetime
/2) : 0xFFFFFFFF;
124 ((struct dhcp6_opt_ia_na
*)p_opt
)->T2
= (config
->dhcp6_preferred_lifetime
> 0) ? htonl((config
->dhcp6_preferred_lifetime
*4)/5) : 0xFFFFFFFF;
126 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
)
128 p_opt
->len
= htons(sizeof(struct dhcp6_opt_ia_na
) - sizeof(*p_opt
) + sizeof(struct dhcp6_opt_status
));
129 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_ia_na
*)p_opt
)[1];
131 ((struct dhcp6_opt_status
*)p_opt
)->hdr
.code
= htons(D6_OPT_STATUS_CODE
);
132 ((struct dhcp6_opt_status
*)p_opt
)->hdr
.len
= htons(2);
133 ((struct dhcp6_opt_status
*)p_opt
)->code
= htons(D6_STATUS_NoBinding
);
134 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_status
*)p_opt
)[1]; // next option
140 if (list_option
.p_mess_hdr
->type
== DHCP6_REQUEST
|| list_option
.p_opt_rapidcommit
)
142 session
[s
].dhcpv6_iana_iaid
= ((struct dhcp6_opt_ia_na
*)list_option
.p_opt_ia_na
)->iaid
;
145 p_opt
->len
= htons(sizeof(struct dhcp6_opt_ia_na
) - sizeof(*p_opt
) + sizeof(struct dhcp6_opt_ia_addr
));
146 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_ia_na
*)p_opt
)[1];
148 ((struct dhcp6_opt_ia_addr
*)p_opt
)->hdr
.code
= htons(D6_OPT_IAADDR
);
149 ((struct dhcp6_opt_ia_addr
*)p_opt
)->hdr
.len
= htons(sizeof(struct dhcp6_opt_ia_addr
) - sizeof(*p_opt
));
151 if (session
[s
].ipv6address
.s6_addr
[0])
153 memcpy(&((struct dhcp6_opt_ia_addr
*)p_opt
)->addr
, &session
[s
].ipv6address
, 16); // copy ipv6 prefix
157 memcpy(&((struct dhcp6_opt_ia_addr
*)p_opt
)->addr
, &config
->ipv6_prefix
, 8); // copy prefix 64
158 addr_ipv4
= htonl(session
[s
].ip
);
159 memcpy(&((struct dhcp6_opt_ia_addr
*)p_opt
)->addr
.s6_addr
[8], &addr_ipv4
, 4); // copy ipv4
162 ((struct dhcp6_opt_ia_addr
*)p_opt
)->pref_lifetime
= (config
->dhcp6_preferred_lifetime
> 0) ? htonl(config
->dhcp6_preferred_lifetime
) : 0xFFFFFFFF;
163 ((struct dhcp6_opt_ia_addr
*)p_opt
)->valid_lifetime
= (config
->dhcp6_valid_lifetime
> 0) ? htonl(config
->dhcp6_valid_lifetime
) : 0xFFFFFFFF;
165 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_ia_addr
*)p_opt
)[1]; // next option
169 if (list_option
.p_opt_ia_ta
&& (list_option
.p_mess_hdr
->type
!= DHCP6_INFORMATION_REQUEST
))
171 p_opt
->code
= htons(D6_OPT_IA_TA
); // D6_OPT_IA_TA
172 p_opt
->len
= htons(sizeof(struct dhcp6_opt_ia_ta
) - sizeof(*p_opt
) + sizeof(struct dhcp6_opt_status
));
173 ((struct dhcp6_opt_ia_ta
*)p_opt
)->iaid
= ((struct dhcp6_opt_ia_ta
*)list_option
.p_opt_ia_ta
)->iaid
;
174 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_ia_ta
*)p_opt
)[1];
175 ((struct dhcp6_opt_status
*)p_opt
)->hdr
.code
= htons(D6_OPT_STATUS_CODE
);
176 ((struct dhcp6_opt_status
*)p_opt
)->hdr
.len
= htons(2);
177 ((struct dhcp6_opt_status
*)p_opt
)->code
= htons(D6_STATUS_UnspecFail
);
178 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_status
*)p_opt
)[1]; // next option
181 if (list_option
.p_opt_oro
)
185 struct in6_addr
*ptr_in6_addr
;
187 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
++)
189 if (ntohs(*ptrw
) == D6_OPT_DNS_SERVERS
)
191 if (config
->default_ipv6_dns1
.s6_addr
[0])
193 p_opt
->code
= htons(D6_OPT_DNS_SERVERS
); // D6_OPT_DNS_SERVERS
194 p_opt
->len
= htons(sizeof(*ptr_in6_addr
));
195 ptr_in6_addr
= (struct in6_addr
*) &p_opt
[1];
196 memcpy(ptr_in6_addr
, &config
->default_ipv6_dns1
, sizeof(*ptr_in6_addr
));
198 if (config
->default_ipv6_dns2
.s6_addr
[0])
200 p_opt
->len
= htons(2*sizeof(*ptr_in6_addr
));
201 ptr_in6_addr
= &ptr_in6_addr
[1];
202 memcpy(ptr_in6_addr
, &config
->default_ipv6_dns2
, sizeof(*ptr_in6_addr
));
205 p_opt
= (struct dhcp6_opt_h
*) &ptr_in6_addr
[1]; // next option
209 if (ntohs(*ptrw
) == D6_OPT_DOMAIN_LIST
)
211 if (*config
->default_ipv6_domain_list
)
214 int len
= dhcpv6_format_dns_search_name(config
->default_ipv6_domain_list
, buffer
);
218 p_opt
->code
= htons(D6_OPT_DOMAIN_LIST
); // D6_OPT_DOMAIN_LIST
219 p_opt
->len
= htons(len
);
220 memcpy((char *)&p_opt
[1], buffer
, len
);
222 p_opt
= (struct dhcp6_opt_h
*) (((uint8_t *) &p_opt
[1]) + len
); // next option
229 if (list_option
.p_opt_rapidcommit
&& (list_option
.p_mess_hdr
->type
== DHCP6_SOLICIT
))
231 p_opt
->code
= htons(D6_OPT_RAPID_COMMIT
); // D6_OPT_RAPID_COMMIT
233 p_opt
= &p_opt
[1]; // next option
236 p_opt
->code
= htons(D6_OPT_PREFERENCE
); // D6_OPT_PREFERENCE
237 p_opt
->len
= htons(1);
238 ((struct dhcp6_opt_preference
*)p_opt
)->pref
= 255;
239 p_opt
= (struct dhcp6_opt_h
*) &((struct dhcp6_opt_preference
*)p_opt
)[1]; // next option
241 // calculation of lenght
242 len
= ((uint8_t *) p_opt
) - ((uint8_t *) p_udp
);
243 p_ip6_hdr
->ip6_plen
= p_udp
->len
= htons(len
);
245 /* Use pseudo hearder for checksum calculation */
246 memset(&pseudo_hdr
, 0, sizeof(pseudo_hdr
));
247 memcpy(&pseudo_hdr
.src
, &p_ip6_hdr
->ip6_src
, 16);
248 memcpy(&pseudo_hdr
.dest
, &p_ip6_hdr
->ip6_dst
, 16);
249 pseudo_hdr
.ulp_length
= htonl(len
); // Lenght whitout Ipv6 header
250 pseudo_hdr
.nexthdr
= IPPROTO_UDP
;
251 // Checksum is over the udp payload plus the pseudo header
252 p_udp
->check
= ipv6_checksum(&pseudo_hdr
, (uint8_t *) p_udp
, len
);
254 // Add ipv6 header to length
255 len
+= sizeof(*p_ip6_hdr
);
256 LOG(3, s
, t
, "Send DHCPv6 message %s\n", (p_mess_hdr
->type
== DHCP6_REPLY
) ? "REPLY" : "ADVERTISE");
257 tunnelsend(b
, len
+ (((uint8_t *) p_ip6_hdr
)-b
), t
); // send it...
260 void dhcpv6_process(sessionidt s
, tunnelidt t
, uint8_t *p
, uint16_t l
)
262 struct ip6_hdr
*p_ip6_hdr_in
;
263 struct dhcp6_mess_hdr
*p_mess_hdr
;
264 struct dhcp6_opt_h
*p_opt
;
268 CSTAT(dhcpv6_process
);
270 p_ip6_hdr_in
= (struct ip6_hdr
*) p
;
271 p_mess_hdr
= (struct dhcp6_mess_hdr
*) (p
+ 48);
273 LOG(3, s
, t
, "Got DHCPv6 message Type: %d\n", p_mess_hdr
->type
);
275 if (!session
[s
].ipv6route
.s6_addr
[0] || !session
[s
].ipv6prefixlen
)
278 p_opt
= (struct dhcp6_opt_h
*) &p_mess_hdr
[1];
279 p_end
= ((uint8_t *)p_ip6_hdr_in
) + ntohs(p_ip6_hdr_in
->ip6_plen
) + sizeof(*p_ip6_hdr_in
);
280 memset(&list_option
, 0, sizeof(list_option
));
281 list_option
.p_mess_hdr
= p_mess_hdr
;
282 while (((uint8_t *)p_opt
) < p_end
)
284 switch(ntohs(p_opt
->code
))
286 case D6_OPT_CLIENTID
:
287 list_option
.p_opt_clientid
= p_opt
;
288 LOG(3, s
, t
, "......Option D6_OPT_CLIENTID\n");
290 case D6_OPT_SERVERID
:
291 list_option
.p_opt_serverid
= p_opt
;
292 LOG(3, s
, t
, "......Option D6_OPT_SERVERID\n");
294 case D6_OPT_RAPID_COMMIT
:
295 list_option
.p_opt_rapidcommit
= p_opt
;
296 LOG(3, s
, t
, "......Option D6_OPT_RAPID_COMMIT\n");
299 list_option
.p_opt_ia_na
= p_opt
;
300 LOG(3, s
, t
, "......Option D6_OPT_IA_NA\n");
303 list_option
.p_opt_ia_ta
= p_opt
;
304 LOG(3, s
, t
, "......Option D6_OPT_IA_TA\n");
307 list_option
.p_opt_oro
= p_opt
;
308 LOG(3, s
, t
, "......Option D6_OPT_ORO\n");
311 list_option
.p_opt_ia_pd
= p_opt
;
312 LOG(3, s
, t
, "......Option D6_OPT_IA_PD\n");
314 case D6_OPT_ELAPSED_TIME
:
315 LOG(3, s
, t
, "......Option D6_OPT_ELAPSED_TIME\n");
319 LOG(3, s
, t
, "......DHCPv6 option: %d\n", ntohs(p_opt
->code
));
322 p_opt
= (struct dhcp6_opt_h
*)(((uint8_t *) p_opt
) + ntohs(p_opt
->len
) + sizeof(*p_opt
));
325 switch(p_mess_hdr
->type
)
329 LOG(3, s
, t
, "..(Type %d = Solicit)\n", p_mess_hdr
->type
);
331 if (!list_option
.p_opt_clientid
)
333 LOG(3, s
, t
, "DHCPv6: error no Client-ID\n");
336 else if (list_option
.p_opt_rapidcommit
)
338 if (!session
[s
].dhcpv6_client_id
.opt_hdr
.len
)
340 len
= ntohs(list_option
.p_opt_clientid
->len
);
342 if ((len
> 0) && (len
<= sizeof(struct dhcp6_duid
)))
344 memcpy(&session
[s
].dhcpv6_client_id
, list_option
.p_opt_clientid
, sizeof(struct dhcp6_opt_h
) + len
);
348 LOG(3, s
, t
, "DHCPv6: Error malformed Client-ID option\n");
352 else if (session
[s
].dhcpv6_client_id
.opt_hdr
.len
!= list_option
.p_opt_clientid
->len
||
353 memcmp(&session
[s
].dhcpv6_client_id
, list_option
.p_opt_clientid
, sizeof(struct dhcp6_opt_h
) + ntohs(list_option
.p_opt_clientid
->len
)))
355 LOG(3, s
, t
, "DHCPv6: Error unmatched Client-ID option\n");
360 if (list_option
.p_opt_serverid
)
362 LOG(3, s
, t
, "DHCPv6: Error unexpected Server-ID option on Solicit\n");
366 dhcp6_send_reply(s
, t
, &p_ip6_hdr_in
->ip6_src
);
372 LOG(3, s
, t
, "..(Type %d = Request)\n", p_mess_hdr
->type
);
374 if (!list_option
.p_opt_clientid
)
376 LOG(3, s
, t
, "DHCPv6: error no Client-ID\n");
380 if (!list_option
.p_opt_serverid
)
382 LOG(3, s
, t
, "DHCPv6: error no Server-ID\n");
385 else if (dhcp6_local_serverid
.opt_hdr
.len
!= list_option
.p_opt_serverid
->len
||
386 memcmp(&dhcp6_local_serverid
, list_option
.p_opt_serverid
, sizeof(struct dhcp6_opt_h
) + ntohs(list_option
.p_opt_serverid
->len
)))
388 LOG(3, s
, t
, "DHCPv6: Error unmatched Server-ID option\n");
392 if (!session
[s
].dhcpv6_client_id
.opt_hdr
.len
)
394 len
= ntohs(list_option
.p_opt_clientid
->len
);
396 if ((len
> 0) && (len
<= sizeof(struct dhcp6_duid
)))
398 memcpy(&session
[s
].dhcpv6_client_id
, list_option
.p_opt_clientid
, sizeof(struct dhcp6_opt_h
) + len
);
402 LOG(3, s
, t
, "DHCPv6: Error malformed Client-ID option\n");
406 else if ( session
[s
].dhcpv6_client_id
.opt_hdr
.len
!= list_option
.p_opt_clientid
->len
||
407 memcmp(&session
[s
].dhcpv6_client_id
, list_option
.p_opt_clientid
, sizeof(struct dhcp6_opt_h
) + ntohs(list_option
.p_opt_clientid
->len
)))
409 LOG(3, s
, t
, "DHCPv6: Error unmatched Client-ID option\n");
413 dhcp6_send_reply(s
, t
, &p_ip6_hdr_in
->ip6_src
);
419 LOG(3, s
, t
, "..(Type %d = Renew)\n", p_mess_hdr
->type
);
421 if (!list_option
.p_opt_clientid
)
423 LOG(3, s
, t
, "DHCPv6: error no Client-ID\n");
426 else if ( session
[s
].dhcpv6_client_id
.opt_hdr
.len
!= list_option
.p_opt_clientid
->len
||
427 memcmp(&session
[s
].dhcpv6_client_id
, list_option
.p_opt_clientid
, sizeof(struct dhcp6_opt_h
) + ntohs(list_option
.p_opt_clientid
->len
)))
429 LOG(3, s
, t
, "DHCPv6: Error unmatched Client-ID option\n");
433 if (!list_option
.p_opt_serverid
)
435 LOG(3, s
, t
, "DHCPv6: error no Server-ID\n");
438 else if (dhcp6_local_serverid
.opt_hdr
.len
!= list_option
.p_opt_serverid
->len
||
439 memcmp(&dhcp6_local_serverid
, list_option
.p_opt_serverid
, sizeof(struct dhcp6_opt_h
) + ntohs(list_option
.p_opt_serverid
->len
)))
441 LOG(3, s
, t
, "DHCPv6: Error unmatched Server-ID option\n");
445 dhcp6_send_reply(s
, t
, &p_ip6_hdr_in
->ip6_src
);
449 case DHCP6_INFORMATION_REQUEST
:
451 LOG(3, s
, t
, "..(Type %d = Information Request)\n", p_mess_hdr
->type
);
453 if (!list_option
.p_opt_clientid
)
455 LOG(3, s
, t
, "DHCPv6: error no Client-ID\n");
459 dhcp6_send_reply(s
, t
, &p_ip6_hdr_in
->ip6_src
);
465 LOG(3, s
, t
, "..(Type %d = Rebind)\n", p_mess_hdr
->type
);
471 LOG(3, s
, t
, "..(Type %d = Release)\n", p_mess_hdr
->type
);
477 LOG(3, s
, t
, "..(Type %d = Decline)\n", p_mess_hdr
->type
);
482 LOG(3, s
, t
, "Got unknown DHCPv6 Type: %d\n", *(p
+ 38));
489 static int dhcpv6_format_dns_search_name(const char *strdns
, uint8_t *buffer
)
491 int n
= strlen(strdns
);
494 if (strdns
[n
- 1] == '.') n
++;
498 LOG(3, 0, 0, "DHCPv6: DNS search '%s' is too long\n", strdns
);
504 ptr
= strchr(strdns
, '.');
506 if (!ptr
) ptr
= strchr(strdns
, 0);
508 if (ptr
- strdns
> 63)
510 LOG(3, 0, 0, "DHCPv6: DNS search '%s' is invalid\n", strdns
);
514 *buffer
= ptr
- strdns
;
515 memcpy(buffer
+ 1, strdns
, ptr
- strdns
);
516 buffer
+= 1 + (ptr
- strdns
);
519 if (!*ptr
|| !*strdns
)
529 void dhcpv6_init(void)
533 dhcp6_local_serverid
.opt_hdr
.code
= htons(D6_OPT_SERVERID
);
534 dhcp6_local_serverid
.opt_hdr
.len
= htons(4 + sizeof(id
));
535 dhcp6_local_serverid
.duid
.type
= htons(DUID_LL
);
536 dhcp6_local_serverid
.duid
.u
.ll
.htype
= htons(27);
538 if (config
->dhcp6_server_duid
)
539 id
= htobe32(config
->dhcp6_server_duid
);
541 id
= htobe32(0xFDFDFAFA);
543 memcpy(dhcp6_local_serverid
.duid
.u
.ll
.addr
, &id
, sizeof(id
));