diff options
Diffstat (limited to 'src/libsystemd-network/sd-dhcp-lease.c')
-rw-r--r-- | src/libsystemd-network/sd-dhcp-lease.c | 117 |
1 files changed, 108 insertions, 9 deletions
diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index febf9f87f3..0d1e3746aa 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -203,6 +203,14 @@ sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) { sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) { if (lease && REFCNT_DEC(lease->n_ref) == 0) { + while (lease->private_options) { + struct sd_dhcp_raw_option *option = lease->private_options; + + LIST_REMOVE(options, lease->private_options, option); + + free(option->data); + free(option); + } free(lease->hostname); free(lease->domainname); free(lease->dns); @@ -607,11 +615,49 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option, } break; + + default: + if (code < DHCP_OPTION_PRIVATE_BASE || code > DHCP_OPTION_PRIVATE_LAST) + break; + + r = dhcp_lease_insert_private_option(lease, code, option, len); + if (r < 0) + return r; } return 0; } +int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, + const uint8_t *data, uint8_t len) { + struct sd_dhcp_raw_option *cur, *option; + + LIST_FOREACH(options, cur, lease->private_options) { + if (tag < cur->tag) + break; + else if (tag == cur->tag) { + log_error("Ignoring duplicate option, tagged %d.", tag); + return 0; + } + } + + option = new(struct sd_dhcp_raw_option, 1); + if (!option) + return -ENOMEM; + + option->tag = tag; + option->length = len; + option->data = memdup(data, len); + if (!option->data) { + free(option); + return -ENOMEM; + } + + LIST_INSERT_BEFORE(options, lease->private_options, cur, option); + + return 0; +} + int dhcp_lease_new(sd_dhcp_lease **ret) { sd_dhcp_lease *lease; @@ -621,6 +667,7 @@ int dhcp_lease_new(sd_dhcp_lease **ret) { lease->router = INADDR_ANY; lease->n_ref = REFCNT_INIT; + LIST_HEAD_INIT(lease->private_options); *ret = lease; return 0; @@ -629,6 +676,7 @@ int dhcp_lease_new(sd_dhcp_lease **ret) { int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { _cleanup_free_ char *temp_path = NULL; _cleanup_fclose_ FILE *f = NULL; + struct sd_dhcp_raw_option *option; struct in_addr address; const struct in_addr *addresses; const uint8_t *client_id, *data; @@ -730,6 +778,14 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex); } + LIST_FOREACH(options, option, lease->private_options) { + char key[strlen("OPTION_000")]; + snprintf(key, sizeof(key), "OPTION_%"PRIu8, option->tag); + r = serialize_dhcp_option(f, key, option->data, option->length); + if (r < 0) + goto fail; + } + r = fflush_and_check(f); if (r < 0) goto fail; @@ -754,9 +810,11 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { *server_address = NULL, *next_server = NULL, *dns = NULL, *ntp = NULL, *mtu = NULL, *routes = NULL, *client_id_hex = NULL, - *vendor_specific_hex = NULL; + *vendor_specific_hex = NULL, + *options[DHCP_OPTION_PRIVATE_LAST - + DHCP_OPTION_PRIVATE_BASE + 1] = { NULL }; struct in_addr addr; - int r; + int r, i; assert(lease_file); assert(ret); @@ -780,6 +838,37 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { "ROUTES", &routes, "CLIENTID", &client_id_hex, "VENDOR_SPECIFIC", &vendor_specific_hex, + "OPTION_224", &options[0], + "OPTION_225", &options[1], + "OPTION_226", &options[2], + "OPTION_227", &options[3], + "OPTION_228", &options[4], + "OPTION_229", &options[5], + "OPTION_230", &options[6], + "OPTION_231", &options[7], + "OPTION_232", &options[8], + "OPTION_233", &options[9], + "OPTION_234", &options[10], + "OPTION_235", &options[11], + "OPTION_236", &options[12], + "OPTION_237", &options[13], + "OPTION_238", &options[14], + "OPTION_239", &options[15], + "OPTION_240", &options[16], + "OPTION_241", &options[17], + "OPTION_242", &options[18], + "OPTION_243", &options[19], + "OPTION_244", &options[20], + "OPTION_245", &options[21], + "OPTION_246", &options[22], + "OPTION_247", &options[23], + "OPTION_248", &options[24], + "OPTION_249", &options[25], + "OPTION_250", &options[26], + "OPTION_251", &options[27], + "OPTION_252", &options[28], + "OPTION_253", &options[29], + "OPTION_254", &options[30], NULL); if (r < 0) { if (r == -ENOENT) @@ -854,19 +943,29 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { } if (client_id_hex) { - if (strlen(client_id_hex) % 2) - return -EINVAL; - - r = unhexmem(client_id_hex, strlen(client_id_hex), (void**) &lease->client_id, &lease->client_id_len); + r = deserialize_dhcp_option(&lease->client_id, &lease->client_id_len, client_id_hex); if (r < 0) return r; } if (vendor_specific_hex) { - if (strlen(vendor_specific_hex) % 2) - return -EINVAL; + r = deserialize_dhcp_option(&lease->vendor_specific, &lease->vendor_specific_len, vendor_specific_hex); + if (r < 0) + return r; + } + + for (i = 0; i <= DHCP_OPTION_PRIVATE_LAST - DHCP_OPTION_PRIVATE_BASE; i++) { + uint8_t *data; + size_t len; + + if (!options[i]) + continue; + + r = deserialize_dhcp_option(&data, &len, options[i]); + if (r < 0) + return r; - r = unhexmem(vendor_specific_hex, strlen(vendor_specific_hex), (void**) &lease->vendor_specific, &lease->vendor_specific_len); + r = dhcp_lease_insert_private_option(lease, DHCP_OPTION_PRIVATE_BASE + i, data, len); if (r < 0) return r; } |