X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd-network%2Fsd-dhcp-client.c;h=5f90617b9e3b2833e8515392ff25c63ea2b1b757;hp=8503f19c2751110d99ac3faa7db9433d7a50c63c;hb=804138a08c1fd6a4a3c19ead91eeb8ef312c36a0;hpb=ba6c0fd6303c63576983c7be892d80d954c1e4c5 diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 8503f19c2..5f90617b9 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -36,9 +36,10 @@ #include "dhcp-protocol.h" #include "dhcp-internal.h" #include "dhcp-lease-internal.h" +#include "dhcp-identifier.h" #include "sd-dhcp-client.h" -#define MAX_CLIENT_ID_LEN 64 /* Arbitrary limit */ +#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */ #define MAX_MAC_ADDR_LEN INFINIBAND_ALEN struct sd_dhcp_client { @@ -60,29 +61,31 @@ struct sd_dhcp_client { uint8_t mac_addr[MAX_MAC_ADDR_LEN]; size_t mac_addr_len; uint16_t arp_type; - union { - struct { - uint8_t type; /* 0: Generic (non-LL) (RFC 2132) */ - uint8_t data[MAX_CLIENT_ID_LEN]; - } _packed_ gen; - struct { - uint8_t type; /* 1: Ethernet Link-Layer (RFC 2132) */ - uint8_t haddr[ETH_ALEN]; - } _packed_ eth; - struct { - uint8_t type; /* 2 - 254: ARP/Link-Layer (RFC 2132) */ - uint8_t haddr[0]; - } _packed_ ll; - struct { - uint8_t type; /* 255: Node-specific (RFC 4361) */ - uint8_t iaid[4]; - uint8_t duid[MAX_CLIENT_ID_LEN - 4]; - } _packed_ ns; - struct { - uint8_t type; - uint8_t data[MAX_CLIENT_ID_LEN]; - } _packed_ raw; - } client_id; + struct { + uint8_t type; + union { + struct { + /* 0: Generic (non-LL) (RFC 2132) */ + uint8_t data[MAX_CLIENT_ID_LEN]; + } _packed_ gen; + struct { + /* 1: Ethernet Link-Layer (RFC 2132) */ + uint8_t haddr[ETH_ALEN]; + } _packed_ eth; + struct { + /* 2 - 254: ARP/Link-Layer (RFC 2132) */ + uint8_t haddr[0]; + } _packed_ ll; + struct { + /* 255: Node-specific (RFC 4361) */ + uint32_t iaid; + struct duid duid; + } _packed_ ns; + struct { + uint8_t data[MAX_CLIENT_ID_LEN]; + } _packed_ raw; + }; + } _packed_ client_id; size_t client_id_len; char *hostname; char *vendor_class_identifier; @@ -239,10 +242,9 @@ int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type, *data = NULL; *data_len = 0; if (client->client_id_len) { - *type = client->client_id.raw.type; + *type = client->client_id.type; *data = client->client_id.raw.data; - *data_len = client->client_id_len - - sizeof (client->client_id.raw.type); + *data_len = client->client_id_len - sizeof(client->client_id.type); } return 0; @@ -270,8 +272,8 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, break; } - if (client->client_id_len == data_len + sizeof (client->client_id.raw.type) && - client->client_id.raw.type == type && + if (client->client_id_len == data_len + sizeof(client->client_id.type) && + client->client_id.type == type && memcmp(&client->client_id.raw.data, data, data_len) == 0) return 0; @@ -282,9 +284,9 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, client_stop(client, DHCP_EVENT_STOP); } - client->client_id.raw.type = type; + client->client_id.type = type; memcpy(&client->client_id.raw.data, data, data_len); - client->client_id_len = data_len + sizeof (client->client_id.raw.type); + client->client_id_len = data_len + sizeof (client->client_id.type); if (need_restart && client->state != DHCP_STATE_STOPPED) sd_dhcp_client_start(client); @@ -461,12 +463,21 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, if (client->arp_type == ARPHRD_ETHER) memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN); - /* If no client identifier exists, construct one from an ethernet - address if present */ - if (client->client_id_len == 0 && client->arp_type == ARPHRD_ETHER) { - client->client_id.eth.type = ARPHRD_ETHER; - memcpy(&client->client_id.eth.haddr, &client->mac_addr, ETH_ALEN); - client->client_id_len = sizeof (client->client_id.eth); + /* If no client identifier exists, construct an RFC 4361-compliant one */ + if (client->client_id_len == 0) { + size_t duid_len; + + client->client_id.type = 255; + + r = dhcp_identifier_set_iaid(client->index, client->mac_addr, client->mac_addr_len, &client->client_id.ns.iaid); + if (r < 0) + return r; + + r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &duid_len); + if (r < 0) + return r; + + client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + duid_len; } /* Some DHCP servers will refuse to issue an DHCP lease if the Client @@ -475,7 +486,7 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0, DHCP_OPTION_CLIENT_IDENTIFIER, client->client_id_len, - &client->client_id.raw); + &client->client_id); if (r < 0) return r; } @@ -500,7 +511,7 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, Note (from ConnMan): Some DHCP servers will send bigger DHCP packets than the defined default size unless the Maximum Messge Size option - is explicitely set + is explicitly set RFC3442 "Requirements to Avoid Sizing Constraints": Because a full routing table can be quite large, the standard 576 @@ -1029,6 +1040,14 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, if (r < 0) return r; + if (client->client_id_len) { + r = dhcp_lease_set_client_id(lease, + (uint8_t *) &client->client_id, + client->client_id_len); + if (r < 0) + return r; + } + r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease); if (r != DHCP_OFFER) { log_dhcp_client(client, "received message was not an OFFER, ignoring"); @@ -1088,6 +1107,14 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, if (r < 0) return r; + if (client->client_id_len) { + r = dhcp_lease_set_client_id(lease, + (uint8_t *) &client->client_id, + client->client_id_len); + if (r < 0) + return r; + } + r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease); if (r == DHCP_NAK) { log_dhcp_client(client, "NAK"); @@ -1366,8 +1393,10 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, client->last_addr = client->lease->address; r = client_set_lease_timeouts(client); - if (r < 0) + if (r < 0) { + log_dhcp_client(client, "could not set lease timeouts"); goto error; + } r = dhcp_network_bind_udp_socket(client->lease->address, DHCP_PORT_CLIENT); @@ -1595,7 +1624,7 @@ int sd_dhcp_client_start(sd_dhcp_client *client) { r = client_start(client); if (r >= 0) - log_dhcp_client(client, "STARTED on ifindex %u", client->index); + log_dhcp_client(client, "STARTED on ifindex %i", client->index); return r; } @@ -1654,7 +1683,7 @@ sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) { } sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) { - if (client && REFCNT_DEC(client->n_ref) <= 0) { + if (client && REFCNT_DEC(client->n_ref) == 0) { log_dhcp_client(client, "FREE"); client_initialize(client);