X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd-network%2Fsd-dhcp-client.c;h=0eba4c379d890c44b574575a09440bcac8e75ed9;hb=1b3a797f6f3c32dc10d8af928d936d87b1edea43;hp=8a9887d19f2892cd2682c2d22d99b32840060666;hpb=db73295accbec0c6513817f0a64a92018592bb26;p=elogind.git diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 8a9887d19..0eba4c379 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,8 @@ #include "dhcp-lease-internal.h" #include "sd-dhcp-client.h" +#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN + struct sd_dhcp_client { RefCount n_ref; @@ -57,6 +60,9 @@ struct sd_dhcp_client { uint8_t type; struct ether_addr mac_addr; } _packed_ client_id; + uint8_t mac_addr[MAX_MAC_ADDR_LEN]; + size_t mac_addr_len; + uint16_t arp_type; char *hostname; char *vendor_class_identifier; uint32_t mtu; @@ -163,15 +169,25 @@ int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) { return 0; } -int sd_dhcp_client_set_mac(sd_dhcp_client *client, - const struct ether_addr *addr) { +int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr, + size_t addr_len, uint16_t arp_type) { DHCP_CLIENT_DONT_DESTROY(client); bool need_restart = false; assert_return(client, -EINVAL); assert_return(addr, -EINVAL); + assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL); + assert_return(arp_type > 0, -EINVAL); + + if (arp_type == ARPHRD_ETHER) + assert_return(addr_len == ETH_ALEN, -EINVAL); + else if (arp_type == ARPHRD_INFINIBAND) + assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); + else + return -EINVAL; - if (memcmp(&client->client_id.mac_addr, addr, ETH_ALEN) == 0) + if (client->mac_addr_len == addr_len && + memcmp(&client->mac_addr, addr, addr_len) == 0) return 0; if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { @@ -181,6 +197,10 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client, client_stop(client, DHCP_EVENT_STOP); } + memcpy(&client->mac_addr, addr, addr_len); + client->mac_addr_len = addr_len; + client->arp_type = arp_type; + memcpy(&client->client_id.mac_addr, addr, ETH_ALEN); client->client_id.type = 0x01; @@ -318,7 +338,7 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, return -ENOMEM; r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type, - optlen, &optoffset); + client->arp_type, optlen, &optoffset); if (r < 0) return r; @@ -337,14 +357,17 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, Note: some interfaces needs this to be enabled, but some networks needs this to be disabled as broadcasts are filteretd, so this needs to be configurable */ - if (client->request_broadcast) + if (client->request_broadcast || client->arp_type != ARPHRD_ETHER) packet->dhcp.flags = htobe16(0x8000); /* RFC2132 section 4.1.1: The client MUST include its hardware address in the ’chaddr’ field, if - necessary for delivery of DHCP reply messages. + necessary for delivery of DHCP reply messages. Non-Ethernet + interfaces will leave 'chaddr' empty and use the client identifier + instead (eg, RFC 4390 section 2.1). */ - memcpy(&packet->dhcp.chaddr, &client->client_id.mac_addr, ETH_ALEN); + if (client->arp_type == ARPHRD_ETHER) + memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN); /* Some DHCP servers will refuse to issue an DHCP lease if the Client Identifier option is not set */ @@ -700,6 +723,11 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, if (r < 0) goto error; + r = sd_event_source_set_name(client->timeout_resend, + "dhcp4-resend-timer"); + if (r < 0) + goto error; + switch (client->state) { case DHCP_STATE_INIT: r = client_send_discover(client); @@ -773,6 +801,11 @@ static int client_initialize_io_events(sd_dhcp_client *client, if (r < 0) goto error; + r = sd_event_source_set_name(client->receive_message, + "dhcp4-receive-message"); + if (r < 0) + goto error; + error: if (r < 0) client_stop(client, r); @@ -799,6 +832,11 @@ static int client_initialize_time_events(sd_dhcp_client *client) { r = sd_event_source_set_priority(client->timeout_resend, client->event_priority); + r = sd_event_source_set_name(client->timeout_resend, + "dhcp4-resend-timer"); + if (r < 0) + goto error; + error: if (r < 0) client_stop(client, r); @@ -828,7 +866,9 @@ static int client_start(sd_dhcp_client *client) { client->xid = random_u32(); - r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr); + r = dhcp_network_bind_raw_socket(client->index, &client->link, + client->xid, client->mac_addr, + client->mac_addr_len, client->arp_type); if (r < 0) { client_stop(client, r); return r; @@ -872,7 +912,9 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) client->state = DHCP_STATE_REBINDING; client->attempt = 1; - r = dhcp_network_bind_raw_socket(client->index, &client->link, client->xid, client->client_id.mac_addr); + r = dhcp_network_bind_raw_socket(client->index, &client->link, + client->xid, client->mac_addr, + client->mac_addr_len, client->arp_type); if (r < 0) { client_stop(client, r); return 0; @@ -904,7 +946,7 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease); if (r != DHCP_OFFER) { - log_dhcp_client(client, "receieved message was not an OFFER, ignoring"); + log_dhcp_client(client, "received message was not an OFFER, ignoring"); return -ENOMSG; } @@ -915,7 +957,7 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, if (lease->address == INADDR_ANY || lease->server_address == INADDR_ANY || lease->lifetime == 0) { - log_dhcp_client(client, "receieved lease lacks address, server " + log_dhcp_client(client, "received lease lacks address, server " "address or lease lifetime, ignoring"); return -ENOMSG; } @@ -923,7 +965,7 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, if (lease->subnet_mask == INADDR_ANY) { r = dhcp_lease_set_default_subnet_mask(lease); if (r < 0) { - log_dhcp_client(client, "receieved lease lacks subnet " + log_dhcp_client(client, "received lease lacks subnet " "mask, and a fallback one can not be " "generated, ignoring"); return -ENOMSG; @@ -968,7 +1010,7 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, } if (r != DHCP_ACK) { - log_dhcp_client(client, "receieved message was not an ACK, ignoring"); + log_dhcp_client(client, "received message was not an ACK, ignoring"); return -ENOMSG; } @@ -979,7 +1021,7 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, if (lease->address == INADDR_ANY || lease->server_address == INADDR_ANY || lease->lifetime == 0) { - log_dhcp_client(client, "receieved lease lacks address, server " + log_dhcp_client(client, "received lease lacks address, server " "address or lease lifetime, ignoring"); return -ENOMSG; } @@ -987,7 +1029,7 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, if (lease->subnet_mask == INADDR_ANY) { r = dhcp_lease_set_default_subnet_mask(lease); if (r < 0) { - log_dhcp_client(client, "receieved lease lacks subnet " + log_dhcp_client(client, "received lease lacks subnet " "mask, and a fallback one can not be " "generated, ignoring"); return -ENOMSG; @@ -1107,6 +1149,11 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { if (r < 0) return r; + r = sd_event_source_set_name(client->timeout_expire, + "dhcp4-lifetime"); + if (r < 0) + return r; + log_dhcp_client(client, "lease expires in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, 0)); @@ -1130,6 +1177,11 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { if (r < 0) return r; + r = sd_event_source_set_name(client->timeout_t2, + "dhcp4-t2-timeout"); + if (r < 0) + return r; + log_dhcp_client(client, "T2 expires in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, 0)); @@ -1152,6 +1204,11 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { if (r < 0) return r; + r = sd_event_source_set_name(client->timeout_t1, + "dhcp4-t1-timer"); + if (r < 0) + return r; + log_dhcp_client(client, "T1 expires in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, 0)); @@ -1192,6 +1249,11 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, client->event_priority); if (r < 0) goto error; + + r = sd_event_source_set_name(client->timeout_resend, + "dhcp4-resend-timer"); + if (r < 0) + goto error; } else if (r == -ENOMSG) /* invalid message, let's ignore it */ return 0; @@ -1296,6 +1358,9 @@ static int client_receive_message_udp(sd_event_source *s, int fd, sd_dhcp_client *client = userdata; _cleanup_free_ DHCPMessage *message = NULL; int buflen = 0, len, r; + const struct ether_addr zero_mac = { { 0, 0, 0, 0, 0, 0 } }; + const struct ether_addr *expected_chaddr = NULL; + uint8_t expected_hlen = 0; assert(s); assert(client); @@ -1332,13 +1397,26 @@ static int client_receive_message_udp(sd_event_source *s, int fd, return 0; } - if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) { - log_dhcp_client(client, "not an ethernet packet"); + if (message->htype != client->arp_type) { + log_dhcp_client(client, "packet type does not match client type"); + return 0; + } + + if (client->arp_type == ARPHRD_ETHER) { + expected_hlen = ETH_ALEN; + expected_chaddr = (const struct ether_addr *) &client->mac_addr; + } else { + /* Non-ethernet links expect zero chaddr */ + expected_hlen = 0; + expected_chaddr = &zero_mac; + } + + if (message->hlen != expected_hlen) { + log_dhcp_client(client, "unexpected packet hlen %d", message->hlen); return 0; } - if (memcmp(&message->chaddr[0], &client->client_id.mac_addr, - ETH_ALEN)) { + if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN)) { log_dhcp_client(client, "received chaddr does not match " "expected: ignoring"); return 0; @@ -1420,7 +1498,6 @@ static int client_receive_message_raw(sd_event_source *s, int fd, } int sd_dhcp_client_start(sd_dhcp_client *client) { - char buffer[ETHER_ADDR_TO_STRING_MAX]; int r; assert_return(client, -EINVAL); @@ -1434,9 +1511,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 with address %s", - client->index, - ether_addr_to_string(&client->client_id.mac_addr, buffer)); + log_dhcp_client(client, "STARTED on ifindex %u", client->index); return r; }