diff options
Diffstat (limited to 'src/libsystemd-network')
-rw-r--r-- | src/libsystemd-network/dhcp-lease-internal.h | 12 | ||||
-rw-r--r-- | src/libsystemd-network/dhcp-protocol.h | 2 | ||||
-rw-r--r-- | src/libsystemd-network/network-internal.c | 27 | ||||
-rw-r--r-- | src/libsystemd-network/network-internal.h | 3 | ||||
-rw-r--r-- | src/libsystemd-network/sd-dhcp-lease.c | 146 | ||||
-rw-r--r-- | src/libsystemd-network/sd-dhcp-server.c | 10 | ||||
-rw-r--r-- | src/libsystemd-network/sd-dhcp6-client.c | 11 | ||||
-rw-r--r-- | src/libsystemd-network/sd-ipv4ll.c | 5 | ||||
-rw-r--r-- | src/libsystemd-network/sd-lldp.c | 68 | ||||
-rw-r--r-- | src/libsystemd-network/sd-pppoe.c | 4 |
10 files changed, 222 insertions, 66 deletions
diff --git a/src/libsystemd-network/dhcp-lease-internal.h b/src/libsystemd-network/dhcp-lease-internal.h index 6e00b1ad30..5a3fcddb1b 100644 --- a/src/libsystemd-network/dhcp-lease-internal.h +++ b/src/libsystemd-network/dhcp-lease-internal.h @@ -27,6 +27,7 @@ #include "refcnt.h" #include "util.h" +#include "list.h" #include "dhcp-protocol.h" @@ -38,6 +39,14 @@ struct sd_dhcp_route { unsigned char dst_prefixlen; }; +struct sd_dhcp_raw_option { + LIST_FIELDS(struct sd_dhcp_raw_option, options); + + uint8_t tag; + uint8_t length; + void *data; +}; + struct sd_dhcp_lease { RefCount n_ref; @@ -74,11 +83,14 @@ struct sd_dhcp_lease { size_t client_id_len; uint8_t *vendor_specific; size_t vendor_specific_len; + LIST_HEAD(struct sd_dhcp_raw_option, private_options); }; int dhcp_lease_new(sd_dhcp_lease **ret); int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option, void *user_data); +int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, + const uint8_t *data, uint8_t len); int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease); diff --git a/src/libsystemd-network/dhcp-protocol.h b/src/libsystemd-network/dhcp-protocol.h index aa37e9b0b5..4308723f91 100644 --- a/src/libsystemd-network/dhcp-protocol.h +++ b/src/libsystemd-network/dhcp-protocol.h @@ -138,5 +138,7 @@ enum { DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60, DHCP_OPTION_CLIENT_IDENTIFIER = 61, DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121, + DHCP_OPTION_PRIVATE_BASE = 224, + DHCP_OPTION_PRIVATE_LAST = 254, DHCP_OPTION_END = 255, }; diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index d579755cc8..3d78bf8b35 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -509,3 +509,30 @@ int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t return 0; } + +int serialize_dhcp_option(FILE *f, const char *key, const uint8_t *data, size_t size) { + _cleanup_free_ char *hex_buf = NULL; + + assert(f); + assert(key); + assert(data); + + hex_buf = hexmem(data, size); + if (hex_buf == NULL) + return -ENOMEM; + + fprintf(f, "%s=%s\n", key, hex_buf); + + return 0; +} + +int deserialize_dhcp_option(uint8_t **data, size_t *data_len, const char *string) { + assert(data); + assert(data_len); + assert(string); + + if (strlen(string) % 2) + return -EINVAL; + + return unhexmem(string, strlen(string), (void **)data, data_len); +} diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index 06aba893ce..7aaecbb10d 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -74,3 +74,6 @@ struct sd_dhcp_route; void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size); int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string); + +int serialize_dhcp_option(FILE *f, const char *key, const uint8_t *data, size_t size); +int deserialize_dhcp_option(uint8_t **data, size_t *data_len, const char *string); diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index 43f7566f65..eae186c9d3 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); @@ -606,11 +614,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; @@ -620,6 +666,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; @@ -628,6 +675,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; @@ -642,13 +690,13 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { r = fopen_temporary(lease_file, &f, &temp_path); if (r < 0) - goto finish; + goto fail; fchmod(fileno(f), 0644); r = sd_dhcp_lease_get_address(lease, &address); if (r < 0) - goto finish; + goto fail; fprintf(f, "# This is private data. Do not parse.\n" @@ -656,7 +704,7 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { r = sd_dhcp_lease_get_netmask(lease, &address); if (r < 0) - goto finish; + goto fail; fprintf(f, "NETMASK=%s\n", inet_ntoa(address)); @@ -712,7 +760,7 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { client_id_hex = hexmem(client_id, client_id_len); if (!client_id_hex) { r = -ENOMEM; - goto finish; + goto fail; } fprintf(f, "CLIENTID=%s\n", client_id_hex); } @@ -724,26 +772,35 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { option_hex = hexmem(data, data_len); if (!option_hex) { r = -ENOMEM; - goto finish; + goto fail; } fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex); } - r = 0; + LIST_FOREACH(options, option, lease->private_options) { + char key[strlen("OPTION_000")+1]; + snprintf(key, sizeof(key), "OPTION_%"PRIu8, option->tag); + r = serialize_dhcp_option(f, key, option->data, option->length); + if (r < 0) + goto fail; + } - fflush(f); + r = fflush_and_check(f); + if (r < 0) + goto fail; - if (ferror(f) || rename(temp_path, lease_file) < 0) { + if (rename(temp_path, lease_file) < 0) { r = -errno; - unlink(lease_file); - unlink(temp_path); + goto fail; } -finish: - if (r < 0) - log_error_errno(r, "Failed to save lease data %s: %m", lease_file); + return 0; + +fail: + if (temp_path) + (void) unlink(temp_path); - return r; + return log_error_errno(r, "Failed to save lease data %s: %m", lease_file); } int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { @@ -752,9 +809,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); @@ -778,6 +837,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) @@ -852,19 +942,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; } diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index cc5e032344..faeab0fd30 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -67,7 +67,7 @@ int sd_dhcp_server_set_address(sd_dhcp_server *server, struct in_addr *address, } bool sd_dhcp_server_is_running(sd_dhcp_server *server) { - assert_return(server, -EINVAL); + assert_return(server, false); return !!server->receive_message; } @@ -796,8 +796,12 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, r = sd_event_now(server->event, clock_boottime_or_monotonic(), &time_now); - if (r < 0) - time_now = now(clock_boottime_or_monotonic()); + if (r < 0) { + if (!existing_lease) + dhcp_lease_free(lease); + return r; + } + lease->expiration = req->lifetime * USEC_PER_SEC + time_now; r = server_send_ack(server, req, address); diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 85162dc555..e2f5862851 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -975,14 +975,9 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) client->retransmit_time = 0; client->retransmit_count = 0; - if (client->state == DHCP6_STATE_STOPPED) { - time_now = now(clock_boottime_or_monotonic()); - } else { - r = sd_event_now(client->event, clock_boottime_or_monotonic(), - &time_now); - if (r < 0) - return r; - } + r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); + if (r < 0) + return r; switch (state) { case DHCP6_STATE_STOPPED: diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index 9e04db96bb..f080c5c0a7 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -187,8 +187,7 @@ static void ipv4ll_set_next_wakeup(sd_ipv4ll *ll, int sec, int random_sec) { if (random_sec) next_timeout += random_u32() % (random_sec * USEC_PER_SEC); - if (sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now) < 0) - time_now = now(clock_boottime_or_monotonic()); + assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now) >= 0); ll->next_wakeup = time_now + next_timeout; ll->next_wakeup_valid = 1; @@ -508,7 +507,7 @@ error: } bool sd_ipv4ll_is_running(sd_ipv4ll *ll) { - assert_return(ll, -EINVAL); + assert_return(ll, false); return !IN_SET(ll->state, IPV4LL_STATE_INIT, IPV4LL_STATE_STOPPED); } diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 6a2c05185d..574e04b541 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -392,7 +392,7 @@ static void lldp_mib_delete_objects(sd_lldp *lldp) { break; if (t <= 0) - t = now(CLOCK_BOOTTIME); + t = now(clock_boottime_or_monotonic()); if (p->until > t) break; @@ -440,7 +440,7 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) { r = fopen_temporary(lldp_file, &f, &temp_path); if (r < 0) - goto finish; + goto fail; fchmod(fileno(f), 0644); @@ -457,8 +457,10 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) { mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], type); s = strdup(buf); - if (!s) - return -ENOMEM; + if (!s) { + r = -ENOMEM; + goto fail; + } r = lldp_read_port_id(p->packet, &type, &length, &port_id); if (r < 0) @@ -466,8 +468,10 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) { if (type != LLDP_PORT_SUBTYPE_MAC_ADDRESS) { k = strndup((char *) port_id, length -1); - if (!k) - return -ENOMEM; + if (!k) { + r = -ENOMEM; + goto fail; + } sprintf(buf, "'_Port=%s' '_PType=%d' ", k , type); free(k); @@ -478,13 +482,15 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) { } k = strappend(s, buf); - if (!k) - return -ENOMEM; + if (!k) { + r = -ENOMEM; + goto fail; + } free(s); s = k; - time = now(CLOCK_BOOTTIME); + time = now(clock_boottime_or_monotonic()); /* Don't write expired packets */ if (time - p->until <= 0) @@ -493,8 +499,10 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) { sprintf(buf, "'_TTL="USEC_FMT"' ", p->until); k = strappend(s, buf); - if (!k) - return -ENOMEM; + if (!k) { + r = -ENOMEM; + goto fail; + } free(s); s = k; @@ -504,15 +512,19 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) { k = strappend(s, "'_NAME=N/A' "); else { t = strndup(k, length); - if (!t) - return -ENOMEM; + if (!t) { + r = -ENOMEM; + goto fail; + } k = strjoin(s, "'_NAME=", t, "' ", NULL); free(t); } - if (!k) - return -ENOMEM; + if (!k) { + r = -ENOMEM; + goto fail; + } free(s); s = k; @@ -522,8 +534,10 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) { sprintf(buf, "'_CAP=%x'", data); k = strappend(s, buf); - if (!k) - return -ENOMEM; + if (!k) { + r = -ENOMEM; + goto fail; + } free(s); s = k; @@ -531,21 +545,23 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) { fprintf(f, "%s\n", s); } } - r = 0; - fflush(f); + r = fflush_and_check(f); + if (r < 0) + goto fail; - if (ferror(f) || rename(temp_path, lldp_file) < 0) { + if (rename(temp_path, lldp_file) < 0) { r = -errno; - unlink(lldp_file); - unlink(temp_path); + goto fail; } - finish: - if (r < 0) - log_error("Failed to save lldp data %s: %s", lldp_file, strerror(-r)); + return 0; + + fail: + if (temp_path) + (void) unlink(temp_path); - return r; + return log_error_errno(r, "Failed to save lldp data %s: %m", lldp_file); } int sd_lldp_start(sd_lldp *lldp) { diff --git a/src/libsystemd-network/sd-pppoe.c b/src/libsystemd-network/sd-pppoe.c index 1de8a5e8bf..ff064f563f 100644 --- a/src/libsystemd-network/sd-pppoe.c +++ b/src/libsystemd-network/sd-pppoe.c @@ -346,9 +346,7 @@ static int pppoe_arm_timeout(sd_pppoe *ppp) { assert(ppp); r = sd_event_now(ppp->event, clock_boottime_or_monotonic(), &next_timeout); - if (r == -ENODATA) - next_timeout = now(clock_boottime_or_monotonic()); - else if (r < 0) + if (r < 0) return r; next_timeout += 500 * USEC_PER_MSEC; |