]>
Commit | Line | Data |
---|---|---|
ca5ad760 YW |
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
2 | ||
0e96961d | 3 | #include "dhcp-internal.h" |
e7d5fe17 | 4 | #include "dhcp6-internal.h" |
0e96961d | 5 | #include "escape.h" |
2805536b | 6 | #include "in-addr-util.h" |
ca5ad760 YW |
7 | #include "networkd-dhcp-common.h" |
8 | #include "networkd-network.h" | |
9 | #include "parse-util.h" | |
10 | #include "string-table.h" | |
426588bc | 11 | #include "strv.h" |
ca5ad760 YW |
12 | |
13 | int config_parse_dhcp( | |
14 | const char* unit, | |
15 | const char *filename, | |
16 | unsigned line, | |
17 | const char *section, | |
18 | unsigned section_line, | |
19 | const char *lvalue, | |
20 | int ltype, | |
21 | const char *rvalue, | |
22 | void *data, | |
23 | void *userdata) { | |
24 | ||
2d792895 | 25 | AddressFamily *dhcp = data, s; |
ca5ad760 YW |
26 | |
27 | assert(filename); | |
28 | assert(lvalue); | |
29 | assert(rvalue); | |
30 | assert(data); | |
31 | ||
32 | /* Note that this is mostly like | |
2d792895 | 33 | * config_parse_address_family(), except that it |
ca5ad760 YW |
34 | * understands some old names for the enum values */ |
35 | ||
2d792895 | 36 | s = address_family_from_string(rvalue); |
ca5ad760 YW |
37 | if (s < 0) { |
38 | ||
39 | /* Previously, we had a slightly different enum here, | |
40 | * support its values for compatibility. */ | |
41 | ||
42 | if (streq(rvalue, "none")) | |
43 | s = ADDRESS_FAMILY_NO; | |
44 | else if (streq(rvalue, "v4")) | |
45 | s = ADDRESS_FAMILY_IPV4; | |
46 | else if (streq(rvalue, "v6")) | |
47 | s = ADDRESS_FAMILY_IPV6; | |
48 | else if (streq(rvalue, "both")) | |
49 | s = ADDRESS_FAMILY_YES; | |
50 | else { | |
d96edb2c | 51 | log_syntax(unit, LOG_WARNING, filename, line, 0, |
ca5ad760 YW |
52 | "Failed to parse DHCP option, ignoring: %s", rvalue); |
53 | return 0; | |
54 | } | |
55 | ||
56 | log_syntax(unit, LOG_WARNING, filename, line, 0, | |
57 | "DHCP=%s is deprecated, please use DHCP=%s instead.", | |
2d792895 | 58 | rvalue, address_family_to_string(s)); |
ca5ad760 YW |
59 | } |
60 | ||
61 | *dhcp = s; | |
62 | return 0; | |
63 | } | |
64 | ||
bdad94d0 YW |
65 | int config_parse_dhcp_route_metric( |
66 | const char* unit, | |
67 | const char *filename, | |
68 | unsigned line, | |
69 | const char *section, | |
70 | unsigned section_line, | |
71 | const char *lvalue, | |
72 | int ltype, | |
73 | const char *rvalue, | |
74 | void *data, | |
75 | void *userdata) { | |
76 | ||
77 | Network *network = data; | |
78 | uint32_t metric; | |
79 | int r; | |
80 | ||
81 | assert(filename); | |
82 | assert(lvalue); | |
83 | assert(rvalue); | |
84 | assert(data); | |
85 | ||
86 | r = safe_atou32(rvalue, &metric); | |
87 | if (r < 0) { | |
d96edb2c | 88 | log_syntax(unit, LOG_WARNING, filename, line, r, |
bdad94d0 YW |
89 | "Failed to parse RouteMetric=%s, ignoring assignment: %m", rvalue); |
90 | return 0; | |
91 | } | |
92 | ||
93 | if (streq_ptr(section, "DHCPv4")) { | |
94 | network->dhcp_route_metric = metric; | |
95 | network->dhcp_route_metric_set = true; | |
96 | } else if (streq_ptr(section, "DHCPv6")) { | |
97 | network->dhcp6_route_metric = metric; | |
98 | network->dhcp6_route_metric_set = true; | |
99 | } else { /* [DHCP] section */ | |
100 | if (!network->dhcp_route_metric_set) | |
101 | network->dhcp_route_metric = metric; | |
102 | if (!network->dhcp6_route_metric_set) | |
103 | network->dhcp6_route_metric = metric; | |
104 | } | |
105 | ||
106 | return 0; | |
107 | } | |
108 | ||
4f7331a8 YW |
109 | int config_parse_dhcp_use_dns( |
110 | const char* unit, | |
111 | const char *filename, | |
112 | unsigned line, | |
113 | const char *section, | |
114 | unsigned section_line, | |
115 | const char *lvalue, | |
116 | int ltype, | |
117 | const char *rvalue, | |
118 | void *data, | |
119 | void *userdata) { | |
120 | ||
121 | Network *network = data; | |
122 | int r; | |
123 | ||
124 | assert(filename); | |
125 | assert(lvalue); | |
126 | assert(rvalue); | |
127 | assert(data); | |
128 | ||
129 | r = parse_boolean(rvalue); | |
130 | if (r < 0) { | |
d96edb2c | 131 | log_syntax(unit, LOG_WARNING, filename, line, r, |
4f7331a8 YW |
132 | "Failed to parse UseDNS=%s, ignoring assignment: %m", rvalue); |
133 | return 0; | |
134 | } | |
135 | ||
bdad94d0 YW |
136 | if (streq_ptr(section, "DHCPv4")) { |
137 | network->dhcp_use_dns = r; | |
138 | network->dhcp_use_dns_set = true; | |
139 | } else if (streq_ptr(section, "DHCPv6")) { | |
140 | network->dhcp6_use_dns = r; | |
141 | network->dhcp6_use_dns_set = true; | |
142 | } else { /* [DHCP] section */ | |
143 | if (!network->dhcp_use_dns_set) | |
144 | network->dhcp_use_dns = r; | |
145 | if (!network->dhcp6_use_dns_set) | |
146 | network->dhcp6_use_dns = r; | |
147 | } | |
4f7331a8 YW |
148 | |
149 | return 0; | |
150 | } | |
151 | ||
152 | int config_parse_dhcp_use_ntp( | |
153 | const char* unit, | |
154 | const char *filename, | |
155 | unsigned line, | |
156 | const char *section, | |
157 | unsigned section_line, | |
158 | const char *lvalue, | |
159 | int ltype, | |
160 | const char *rvalue, | |
161 | void *data, | |
162 | void *userdata) { | |
163 | ||
164 | Network *network = data; | |
165 | int r; | |
166 | ||
167 | assert(filename); | |
168 | assert(lvalue); | |
169 | assert(rvalue); | |
170 | assert(data); | |
171 | ||
172 | r = parse_boolean(rvalue); | |
173 | if (r < 0) { | |
d96edb2c | 174 | log_syntax(unit, LOG_WARNING, filename, line, r, |
4f7331a8 YW |
175 | "Failed to parse UseNTP=%s, ignoring assignment: %m", rvalue); |
176 | return 0; | |
177 | } | |
178 | ||
bdad94d0 YW |
179 | if (streq_ptr(section, "DHCPv4")) { |
180 | network->dhcp_use_ntp = r; | |
181 | network->dhcp_use_ntp_set = true; | |
182 | } else if (streq_ptr(section, "DHCPv6")) { | |
183 | network->dhcp6_use_ntp = r; | |
184 | network->dhcp6_use_ntp_set = true; | |
185 | } else { /* [DHCP] section */ | |
186 | if (!network->dhcp_use_ntp_set) | |
187 | network->dhcp_use_ntp = r; | |
188 | if (!network->dhcp6_use_ntp_set) | |
189 | network->dhcp6_use_ntp = r; | |
190 | } | |
4f7331a8 YW |
191 | |
192 | return 0; | |
193 | } | |
194 | ||
ca5ad760 YW |
195 | int config_parse_section_route_table( |
196 | const char *unit, | |
197 | const char *filename, | |
198 | unsigned line, | |
199 | const char *section, | |
200 | unsigned section_line, | |
201 | const char *lvalue, | |
202 | int ltype, | |
203 | const char *rvalue, | |
204 | void *data, | |
205 | void *userdata) { | |
206 | ||
207 | Network *network = data; | |
208 | uint32_t rt; | |
209 | int r; | |
210 | ||
211 | assert(filename); | |
212 | assert(lvalue); | |
213 | assert(rvalue); | |
214 | assert(data); | |
215 | ||
216 | r = safe_atou32(rvalue, &rt); | |
217 | if (r < 0) { | |
d96edb2c | 218 | log_syntax(unit, LOG_WARNING, filename, line, r, |
ca5ad760 YW |
219 | "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue); |
220 | return 0; | |
221 | } | |
222 | ||
426588bc | 223 | if (STRPTR_IN_SET(section, "DHCP", "DHCPv4")) { |
ca5ad760 YW |
224 | network->dhcp_route_table = rt; |
225 | network->dhcp_route_table_set = true; | |
226 | } else { /* section is IPv6AcceptRA */ | |
227 | network->ipv6_accept_ra_route_table = rt; | |
228 | network->ipv6_accept_ra_route_table_set = true; | |
229 | } | |
230 | ||
231 | return 0; | |
232 | } | |
233 | ||
234 | int config_parse_iaid(const char *unit, | |
235 | const char *filename, | |
236 | unsigned line, | |
237 | const char *section, | |
238 | unsigned section_line, | |
239 | const char *lvalue, | |
240 | int ltype, | |
241 | const char *rvalue, | |
242 | void *data, | |
243 | void *userdata) { | |
244 | Network *network = data; | |
245 | uint32_t iaid; | |
246 | int r; | |
247 | ||
248 | assert(filename); | |
249 | assert(lvalue); | |
250 | assert(rvalue); | |
251 | assert(network); | |
252 | ||
253 | r = safe_atou32(rvalue, &iaid); | |
254 | if (r < 0) { | |
d96edb2c | 255 | log_syntax(unit, LOG_WARNING, filename, line, r, |
ca5ad760 YW |
256 | "Unable to read IAID, ignoring assignment: %s", rvalue); |
257 | return 0; | |
258 | } | |
259 | ||
260 | network->iaid = iaid; | |
261 | network->iaid_set = true; | |
262 | ||
263 | return 0; | |
264 | } | |
265 | ||
f37f2a6b | 266 | int config_parse_dhcp_user_class( |
3175a8c2 SS |
267 | const char *unit, |
268 | const char *filename, | |
269 | unsigned line, | |
270 | const char *section, | |
271 | unsigned section_line, | |
272 | const char *lvalue, | |
273 | int ltype, | |
274 | const char *rvalue, | |
275 | void *data, | |
276 | void *userdata) { | |
277 | ||
f37f2a6b SS |
278 | char ***l = data; |
279 | int r; | |
280 | ||
281 | assert(l); | |
282 | assert(lvalue); | |
283 | assert(rvalue); | |
284 | ||
285 | if (isempty(rvalue)) { | |
286 | *l = strv_free(*l); | |
287 | return 0; | |
288 | } | |
289 | ||
d96edb2c | 290 | for (const char *p = rvalue;;) { |
f37f2a6b SS |
291 | _cleanup_free_ char *w = NULL; |
292 | ||
d96edb2c | 293 | r = extract_first_word(&p, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); |
f37f2a6b SS |
294 | if (r == -ENOMEM) |
295 | return log_oom(); | |
296 | if (r < 0) { | |
d96edb2c | 297 | log_syntax(unit, LOG_WARNING, filename, line, r, |
f37f2a6b | 298 | "Failed to split user classes option, ignoring: %s", rvalue); |
d96edb2c | 299 | return 0; |
f37f2a6b SS |
300 | } |
301 | if (r == 0) | |
d96edb2c | 302 | return 0; |
f37f2a6b SS |
303 | |
304 | if (ltype == AF_INET) { | |
305 | if (strlen(w) > UINT8_MAX) { | |
d96edb2c | 306 | log_syntax(unit, LOG_WARNING, filename, line, 0, |
f37f2a6b SS |
307 | "%s length is not in the range 1-255, ignoring.", w); |
308 | continue; | |
309 | } | |
310 | } else { | |
311 | if (strlen(w) > UINT16_MAX) { | |
d96edb2c | 312 | log_syntax(unit, LOG_WARNING, filename, line, 0, |
f37f2a6b SS |
313 | "%s length is not in the range 1-65535, ignoring.", w); |
314 | continue; | |
315 | } | |
316 | } | |
317 | ||
318 | r = strv_push(l, w); | |
319 | if (r < 0) | |
320 | return log_oom(); | |
321 | ||
322 | w = NULL; | |
323 | } | |
f37f2a6b SS |
324 | } |
325 | ||
ed0d1b2e SS |
326 | int config_parse_dhcp_vendor_class( |
327 | const char *unit, | |
328 | const char *filename, | |
329 | unsigned line, | |
330 | const char *section, | |
331 | unsigned section_line, | |
332 | const char *lvalue, | |
333 | int ltype, | |
334 | const char *rvalue, | |
335 | void *data, | |
336 | void *userdata) { | |
337 | char ***l = data; | |
338 | int r; | |
339 | ||
340 | assert(l); | |
341 | assert(lvalue); | |
342 | assert(rvalue); | |
343 | ||
344 | if (isempty(rvalue)) { | |
345 | *l = strv_free(*l); | |
346 | return 0; | |
347 | } | |
348 | ||
d96edb2c | 349 | for (const char *p = rvalue;;) { |
ed0d1b2e SS |
350 | _cleanup_free_ char *w = NULL; |
351 | ||
d96edb2c | 352 | r = extract_first_word(&p, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); |
ed0d1b2e SS |
353 | if (r == -ENOMEM) |
354 | return log_oom(); | |
355 | if (r < 0) { | |
d96edb2c | 356 | log_syntax(unit, LOG_WARNING, filename, line, r, |
ed0d1b2e | 357 | "Failed to split vendor classes option, ignoring: %s", rvalue); |
d96edb2c | 358 | return 0; |
ed0d1b2e SS |
359 | } |
360 | if (r == 0) | |
d96edb2c | 361 | return 0; |
ed0d1b2e SS |
362 | |
363 | if (strlen(w) > UINT8_MAX) { | |
d96edb2c | 364 | log_syntax(unit, LOG_WARNING, filename, line, 0, |
ed0d1b2e SS |
365 | "%s length is not in the range 1-255, ignoring.", w); |
366 | continue; | |
367 | } | |
368 | ||
369 | r = strv_push(l, w); | |
370 | if (r < 0) | |
371 | return log_oom(); | |
372 | ||
373 | w = NULL; | |
374 | } | |
ed0d1b2e SS |
375 | } |
376 | ||
0e96961d YW |
377 | int config_parse_dhcp_send_option( |
378 | const char *unit, | |
379 | const char *filename, | |
380 | unsigned line, | |
381 | const char *section, | |
382 | unsigned section_line, | |
383 | const char *lvalue, | |
384 | int ltype, | |
385 | const char *rvalue, | |
386 | void *data, | |
387 | void *userdata) { | |
388 | ||
e7d5fe17 AD |
389 | _cleanup_(sd_dhcp_option_unrefp) sd_dhcp_option *opt4 = NULL, *old4 = NULL; |
390 | _cleanup_(sd_dhcp6_option_unrefp) sd_dhcp6_option *opt6 = NULL, *old6 = NULL; | |
b4ccc5de | 391 | uint32_t uint32_data, enterprise_identifier = 0; |
0e96961d | 392 | _cleanup_free_ char *word = NULL, *q = NULL; |
83b56c70 | 393 | OrderedHashmap **options = data; |
b4ccc5de | 394 | uint16_t u16, uint16_data; |
0e96961d YW |
395 | union in_addr_union addr; |
396 | DHCPOptionDataType type; | |
e7d5fe17 | 397 | uint8_t u8, uint8_data; |
0e96961d YW |
398 | const void *udata; |
399 | const char *p; | |
400 | ssize_t sz; | |
401 | int r; | |
402 | ||
403 | assert(filename); | |
404 | assert(lvalue); | |
405 | assert(rvalue); | |
406 | assert(data); | |
407 | ||
408 | if (isempty(rvalue)) { | |
409 | *options = ordered_hashmap_free(*options); | |
410 | return 0; | |
411 | } | |
412 | ||
413 | p = rvalue; | |
b4ccc5de SS |
414 | if (ltype == AF_INET6 && streq(lvalue, "SendVendorOption")) { |
415 | r = extract_first_word(&p, &word, ":", 0); | |
416 | if (r == -ENOMEM) | |
417 | return log_oom(); | |
418 | if (r <= 0 || isempty(p)) { | |
d96edb2c | 419 | log_syntax(unit, LOG_WARNING, filename, line, r, |
b4ccc5de SS |
420 | "Invalid DHCP option, ignoring assignment: %s", rvalue); |
421 | return 0; | |
422 | } | |
423 | ||
424 | r = safe_atou32(word, &enterprise_identifier); | |
425 | if (r < 0) { | |
d96edb2c | 426 | log_syntax(unit, LOG_WARNING, filename, line, r, |
b4ccc5de SS |
427 | "Failed to parse DHCPv6 enterprise identifier data, ignoring assignment: %s", p); |
428 | return 0; | |
429 | } | |
430 | word = mfree(word); | |
431 | } | |
432 | ||
0e96961d YW |
433 | r = extract_first_word(&p, &word, ":", 0); |
434 | if (r == -ENOMEM) | |
435 | return log_oom(); | |
b4ccc5de | 436 | if (r <= 0 || isempty(p)) { |
d96edb2c | 437 | log_syntax(unit, LOG_WARNING, filename, line, r, |
0e96961d YW |
438 | "Invalid DHCP option, ignoring assignment: %s", rvalue); |
439 | return 0; | |
440 | } | |
441 | ||
e7d5fe17 AD |
442 | if (ltype == AF_INET6) { |
443 | r = safe_atou16(word, &u16); | |
444 | if (r < 0) { | |
d96edb2c | 445 | log_syntax(unit, LOG_WARNING, filename, line, r, |
e7d5fe17 AD |
446 | "Invalid DHCP option, ignoring assignment: %s", rvalue); |
447 | return 0; | |
448 | } | |
f37f2a6b | 449 | if (u16 < 1 || u16 >= UINT16_MAX) { |
d96edb2c | 450 | log_syntax(unit, LOG_WARNING, filename, line, 0, |
e7d5fe17 AD |
451 | "Invalid DHCP option, valid range is 1-65535, ignoring assignment: %s", rvalue); |
452 | return 0; | |
453 | } | |
454 | } else { | |
455 | r = safe_atou8(word, &u8); | |
456 | if (r < 0) { | |
d96edb2c | 457 | log_syntax(unit, LOG_WARNING, filename, line, r, |
e7d5fe17 AD |
458 | "Invalid DHCP option, ignoring assignment: %s", rvalue); |
459 | return 0; | |
460 | } | |
ffed0205 | 461 | if (u8 < 1 || u8 >= UINT8_MAX) { |
d96edb2c | 462 | log_syntax(unit, LOG_WARNING, filename, line, 0, |
e7d5fe17 AD |
463 | "Invalid DHCP option, valid range is 1-254, ignoring assignment: %s", rvalue); |
464 | return 0; | |
465 | } | |
0e96961d YW |
466 | } |
467 | ||
3db7d5d2 | 468 | word = mfree(word); |
0e96961d YW |
469 | r = extract_first_word(&p, &word, ":", 0); |
470 | if (r == -ENOMEM) | |
471 | return log_oom(); | |
1eb73422 | 472 | if (r <= 0 || isempty(p)) { |
d96edb2c | 473 | log_syntax(unit, LOG_WARNING, filename, line, r, |
0e96961d YW |
474 | "Invalid DHCP option, ignoring assignment: %s", rvalue); |
475 | return 0; | |
476 | } | |
477 | ||
478 | type = dhcp_option_data_type_from_string(word); | |
479 | if (type < 0) { | |
d96edb2c | 480 | log_syntax(unit, LOG_WARNING, filename, line, 0, |
0e96961d YW |
481 | "Invalid DHCP option data type, ignoring assignment: %s", p); |
482 | return 0; | |
483 | } | |
484 | ||
485 | switch(type) { | |
486 | case DHCP_OPTION_DATA_UINT8:{ | |
487 | r = safe_atou8(p, &uint8_data); | |
488 | if (r < 0) { | |
d96edb2c | 489 | log_syntax(unit, LOG_WARNING, filename, line, r, |
e7d5fe17 | 490 | "Failed to parse DHCP uint8 data, ignoring assignment: %s", p); |
0e96961d YW |
491 | return 0; |
492 | } | |
493 | ||
494 | udata = &uint8_data; | |
495 | sz = sizeof(uint8_t); | |
496 | break; | |
497 | } | |
498 | case DHCP_OPTION_DATA_UINT16:{ | |
499 | r = safe_atou16(p, &uint16_data); | |
500 | if (r < 0) { | |
d96edb2c | 501 | log_syntax(unit, LOG_WARNING, filename, line, r, |
e7d5fe17 | 502 | "Failed to parse DHCP uint16 data, ignoring assignment: %s", p); |
0e96961d YW |
503 | return 0; |
504 | } | |
505 | ||
506 | udata = &uint16_data; | |
507 | sz = sizeof(uint16_t); | |
508 | break; | |
509 | } | |
510 | case DHCP_OPTION_DATA_UINT32: { | |
511 | r = safe_atou32(p, &uint32_data); | |
512 | if (r < 0) { | |
d96edb2c | 513 | log_syntax(unit, LOG_WARNING, filename, line, r, |
e7d5fe17 | 514 | "Failed to parse DHCP uint32 data, ignoring assignment: %s", p); |
0e96961d YW |
515 | return 0; |
516 | } | |
517 | ||
518 | udata = &uint32_data; | |
519 | sz = sizeof(uint32_t); | |
520 | ||
521 | break; | |
522 | } | |
523 | case DHCP_OPTION_DATA_IPV4ADDRESS: { | |
524 | r = in_addr_from_string(AF_INET, p, &addr); | |
525 | if (r < 0) { | |
d96edb2c | 526 | log_syntax(unit, LOG_WARNING, filename, line, r, |
e7d5fe17 | 527 | "Failed to parse DHCP ipv4address data, ignoring assignment: %s", p); |
0e96961d YW |
528 | return 0; |
529 | } | |
530 | ||
531 | udata = &addr.in; | |
532 | sz = sizeof(addr.in.s_addr); | |
533 | break; | |
534 | } | |
e7d5fe17 AD |
535 | case DHCP_OPTION_DATA_IPV6ADDRESS: { |
536 | r = in_addr_from_string(AF_INET6, p, &addr); | |
537 | if (r < 0) { | |
d96edb2c | 538 | log_syntax(unit, LOG_WARNING, filename, line, r, |
e7d5fe17 AD |
539 | "Failed to parse DHCP ipv6address data, ignoring assignment: %s", p); |
540 | return 0; | |
541 | } | |
542 | ||
543 | udata = &addr.in6; | |
544 | sz = sizeof(addr.in6.s6_addr); | |
545 | break; | |
546 | } | |
0e96961d | 547 | case DHCP_OPTION_DATA_STRING: |
732e3a61 | 548 | sz = cunescape(p, UNESCAPE_ACCEPT_NUL, &q); |
0e96961d | 549 | if (sz < 0) { |
d96edb2c | 550 | log_syntax(unit, LOG_WARNING, filename, line, sz, |
e7d5fe17 | 551 | "Failed to decode DHCP option data, ignoring assignment: %s", p); |
0e96961d YW |
552 | } |
553 | ||
554 | udata = q; | |
555 | break; | |
556 | default: | |
557 | return -EINVAL; | |
558 | } | |
559 | ||
e7d5fe17 | 560 | if (ltype == AF_INET6) { |
b4ccc5de | 561 | r = sd_dhcp6_option_new(u16, udata, sz, enterprise_identifier, &opt6); |
e7d5fe17 | 562 | if (r < 0) { |
d96edb2c | 563 | log_syntax(unit, LOG_WARNING, filename, line, r, |
e7d5fe17 AD |
564 | "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue); |
565 | return 0; | |
566 | } | |
0e96961d | 567 | |
e7d5fe17 AD |
568 | r = ordered_hashmap_ensure_allocated(options, &dhcp6_option_hash_ops); |
569 | if (r < 0) | |
570 | return log_oom(); | |
0e96961d | 571 | |
e7d5fe17 AD |
572 | /* Overwrite existing option */ |
573 | old6 = ordered_hashmap_get(*options, UINT_TO_PTR(u16)); | |
574 | r = ordered_hashmap_replace(*options, UINT_TO_PTR(u16), opt6); | |
575 | if (r < 0) { | |
d96edb2c | 576 | log_syntax(unit, LOG_WARNING, filename, line, r, |
e7d5fe17 AD |
577 | "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue); |
578 | return 0; | |
579 | } | |
580 | TAKE_PTR(opt6); | |
581 | } else { | |
582 | r = sd_dhcp_option_new(u8, udata, sz, &opt4); | |
583 | if (r < 0) { | |
d96edb2c | 584 | log_syntax(unit, LOG_WARNING, filename, line, r, |
e7d5fe17 AD |
585 | "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue); |
586 | return 0; | |
587 | } | |
0e96961d | 588 | |
e7d5fe17 AD |
589 | r = ordered_hashmap_ensure_allocated(options, &dhcp_option_hash_ops); |
590 | if (r < 0) | |
591 | return log_oom(); | |
592 | ||
593 | /* Overwrite existing option */ | |
594 | old4 = ordered_hashmap_get(*options, UINT_TO_PTR(u8)); | |
595 | r = ordered_hashmap_replace(*options, UINT_TO_PTR(u8), opt4); | |
596 | if (r < 0) { | |
d96edb2c | 597 | log_syntax(unit, LOG_WARNING, filename, line, r, |
e7d5fe17 AD |
598 | "Failed to store DHCP option '%s', ignoring assignment: %m", rvalue); |
599 | return 0; | |
600 | } | |
601 | TAKE_PTR(opt4); | |
602 | } | |
0e96961d YW |
603 | return 0; |
604 | } | |
605 | ||
35f6a5cb SS |
606 | int config_parse_dhcp_request_options( |
607 | const char *unit, | |
608 | const char *filename, | |
609 | unsigned line, | |
610 | const char *section, | |
611 | unsigned section_line, | |
612 | const char *lvalue, | |
613 | int ltype, | |
614 | const char *rvalue, | |
615 | void *data, | |
616 | void *userdata) { | |
617 | ||
618 | Network *network = data; | |
619 | const char *p; | |
620 | int r; | |
621 | ||
622 | assert(filename); | |
623 | assert(lvalue); | |
624 | assert(rvalue); | |
625 | assert(data); | |
626 | ||
627 | if (isempty(rvalue)) { | |
628 | if (ltype == AF_INET) | |
629 | network->dhcp_request_options = set_free(network->dhcp_request_options); | |
630 | else | |
631 | network->dhcp6_request_options = set_free(network->dhcp6_request_options); | |
632 | ||
633 | return 0; | |
634 | } | |
635 | ||
636 | for (p = rvalue;;) { | |
637 | _cleanup_free_ char *n = NULL; | |
638 | uint32_t i; | |
639 | ||
640 | r = extract_first_word(&p, &n, NULL, 0); | |
d96edb2c YW |
641 | if (r == -ENOMEM) |
642 | return log_oom(); | |
35f6a5cb | 643 | if (r < 0) { |
d96edb2c | 644 | log_syntax(unit, LOG_WARNING, filename, line, r, |
35f6a5cb SS |
645 | "Failed to parse DHCP request option, ignoring assignment: %s", |
646 | rvalue); | |
647 | return 0; | |
648 | } | |
649 | if (r == 0) | |
650 | return 0; | |
651 | ||
652 | r = safe_atou32(n, &i); | |
653 | if (r < 0) { | |
d96edb2c | 654 | log_syntax(unit, LOG_WARNING, filename, line, r, |
35f6a5cb SS |
655 | "DHCP request option is invalid, ignoring assignment: %s", n); |
656 | continue; | |
657 | } | |
658 | ||
ffed0205 | 659 | if (i < 1 || i >= UINT8_MAX) { |
d96edb2c | 660 | log_syntax(unit, LOG_WARNING, filename, line, 0, |
35f6a5cb SS |
661 | "DHCP request option is invalid, valid range is 1-254, ignoring assignment: %s", n); |
662 | continue; | |
663 | } | |
664 | ||
de7fef4b ZJS |
665 | r = set_ensure_put(ltype == AF_INET ? &network->dhcp_request_options : &network->dhcp6_request_options, |
666 | NULL, UINT32_TO_PTR(i)); | |
35f6a5cb | 667 | if (r < 0) |
d96edb2c | 668 | log_syntax(unit, LOG_WARNING, filename, line, r, |
35f6a5cb SS |
669 | "Failed to store DHCP request option '%s', ignoring assignment: %m", n); |
670 | } | |
35f6a5cb SS |
671 | } |
672 | ||
ca5ad760 YW |
673 | DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, |
674 | "Failed to parse DHCP use domains setting"); | |
675 | ||
676 | static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = { | |
677 | [DHCP_USE_DOMAINS_NO] = "no", | |
678 | [DHCP_USE_DOMAINS_ROUTE] = "route", | |
679 | [DHCP_USE_DOMAINS_YES] = "yes", | |
680 | }; | |
681 | ||
682 | DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES); | |
2e5580a8 YW |
683 | |
684 | static const char * const dhcp_option_data_type_table[_DHCP_OPTION_DATA_MAX] = { | |
685 | [DHCP_OPTION_DATA_UINT8] = "uint8", | |
686 | [DHCP_OPTION_DATA_UINT16] = "uint16", | |
687 | [DHCP_OPTION_DATA_UINT32] = "uint32", | |
688 | [DHCP_OPTION_DATA_STRING] = "string", | |
689 | [DHCP_OPTION_DATA_IPV4ADDRESS] = "ipv4address", | |
e7d5fe17 | 690 | [DHCP_OPTION_DATA_IPV6ADDRESS] = "ipv6address", |
2e5580a8 YW |
691 | }; |
692 | ||
693 | DEFINE_STRING_TABLE_LOOKUP(dhcp_option_data_type, DHCPOptionDataType); |