systemd/dhcp: add support for vendor specific DHCP option

This adds support for DHCP option 43 (Vendor Specific Information) to
the internal DHCP client. The option carries an opaque object of n
octets, interpreted by vendor-specific code on the clients and
servers.

(cherry picked from commit 3c2f4a17f9)
This commit is contained in:
Beniamino Galvani 2015-05-21 08:40:02 +02:00
parent 54ebd11026
commit 75f0c79494
4 changed files with 56 additions and 0 deletions

View file

@ -72,6 +72,8 @@ struct sd_dhcp_lease {
char *root_path;
uint8_t *client_id;
size_t client_id_len;
uint8_t *vendor_specific;
size_t vendor_specific_size;
};
int dhcp_lease_new(sd_dhcp_lease **ret);

View file

@ -125,6 +125,7 @@ enum {
DHCP_OPTION_BROADCAST = 28,
DHCP_OPTION_STATIC_ROUTE = 33,
DHCP_OPTION_NTP_SERVER = 42,
DHCP_OPTION_VENDOR_SPECIFIC = 43,
DHCP_OPTION_REQUESTED_IP_ADDRESS = 50,
DHCP_OPTION_IP_ADDRESS_LEASE_TIME = 51,
DHCP_OPTION_OVERLOAD = 52,

View file

@ -191,6 +191,19 @@ int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes
return 0;
}
int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, uint8_t **data) {
assert_return(lease, -EINVAL);
assert_return(data, -EINVAL);
if (lease->vendor_specific) {
*data = lease->vendor_specific;
return lease->vendor_specific_size;
} else
return -ENOENT;
return 0;
}
sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
if (lease)
assert_se(REFCNT_INC(lease->n_ref) >= 2);
@ -286,6 +299,24 @@ static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
return 0;
}
static int lease_parse_binary(const uint8_t *option, size_t len, uint8_t **ret) {
assert (option);
assert (ret);
if (len >= 1) {
uint8_t *data;
data = memdup(option, len);
if (!data)
return -errno;
free(*ret);
*ret = data;
}
return 0;
}
static int lease_parse_in_addrs_aux(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size, size_t mult) {
assert(option);
assert(ret);
@ -568,6 +599,14 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
return r;
break;
case DHCP_OPTION_VENDOR_SPECIFIC:
r = lease_parse_binary(option, len, &lease->vendor_specific);
if (r < 0)
return r;
lease->vendor_specific_size = len;
break;
}
return 0;
@ -595,6 +634,7 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
const uint8_t *client_id;
size_t client_id_len;
const char *string;
uint8_t *data;
uint16_t mtu;
struct sd_dhcp_route *routes;
int r;
@ -667,6 +707,18 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
if (r >= 0)
serialize_dhcp_routes(f, "ROUTES", routes, r);
r = sd_dhcp_lease_get_vendor_specific(lease, &data);
if (r >= 0) {
_cleanup_free_ char *option_hex = NULL;
option_hex = hexmem(data, r);
if (!option_hex) {
r = -ENOMEM;
goto finish;
}
fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex);
}
r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
if (r >= 0) {
_cleanup_free_ char *client_id_hex = NULL;

View file

@ -45,6 +45,7 @@ int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname);
int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname);
int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path);
int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routesgn);
int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, uint8_t **data);
int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id,
size_t *client_id_len);