X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd-network%2Fsd-dhcp-client.c;h=8205ad0e18e0bfb1b1525d8649a1f9ae9845879e;hb=615c1467c81411bf1d19fd7092e8995b5ebadc13;hp=e6225642eb699feb077f8aaec50697fc907bda4c;hpb=fa94c34b083b5b4019975624453e53d0cbad2a5d;p=elogind.git diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index e6225642e..8205ad0e1 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -276,19 +276,10 @@ static void client_stop(sd_dhcp_client *client, int error) { if (error < 0) log_dhcp_client(client, "STOPPED: %s", strerror(-error)); - else { - switch(error) { - case DHCP_EVENT_STOP: - log_dhcp_client(client, "STOPPED"); - break; - case DHCP_EVENT_NO_LEASE: - log_dhcp_client(client, "STOPPED: No lease"); - break; - default: - log_dhcp_client(client, "STOPPED: Unknown reason"); - break; - } - } + else if (error == DHCP_EVENT_STOP) + log_dhcp_client(client, "STOPPED"); + else + log_dhcp_client(client, "STOPPED: Unknown event"); client_notify(client, error); @@ -740,8 +731,8 @@ error: return 0; } -static int client_initialize_events(sd_dhcp_client *client, - sd_event_io_handler_t io_callback) { +static int client_initialize_io_events(sd_dhcp_client *client, + sd_event_io_handler_t io_callback) { int r; assert(client); @@ -758,6 +749,19 @@ static int client_initialize_events(sd_dhcp_client *client, if (r < 0) goto error; +error: + if (r < 0) + client_stop(client, r); + + return 0; +} + +static int client_initialize_time_events(sd_dhcp_client *client) { + int r; + + assert(client); + assert(client->event); + client->timeout_resend = sd_event_source_unref(client->timeout_resend); r = sd_event_add_time(client->event, @@ -779,6 +783,14 @@ error: } +static int client_initialize_events(sd_dhcp_client *client, + sd_event_io_handler_t io_callback) { + client_initialize_io_events(client, io_callback); + client_initialize_time_events(client); + + return 0; +} + static int client_start(sd_dhcp_client *client) { int r; @@ -850,21 +862,11 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) { sd_dhcp_client *client = userdata; DHCP_CLIENT_DONT_DESTROY(client); - int r; client->state = DHCP_STATE_RENEWING; client->attempt = 1; - r = dhcp_network_bind_udp_socket(client->lease->address, - DHCP_PORT_CLIENT); - if (r < 0) { - log_dhcp_client(client, "could not bind UDP socket"); - return 0; - } - - client->fd = r; - - return client_initialize_events(client, client_receive_message_udp); + return client_initialize_time_events(client); } static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, @@ -913,6 +915,19 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, return 0; } +static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, + size_t len) { + int r; + + r = dhcp_option_parse(force, len, NULL, NULL); + if (r != DHCP_FORCERENEW) + return -ENOMSG; + + log_dhcp_client(client, "FORCERENEW"); + + return 0; +} + static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) { _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL; @@ -925,7 +940,7 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease); if (r == DHCP_NAK) { log_dhcp_client(client, "NAK"); - return DHCP_EVENT_NO_LEASE; + return -EADDRNOTAVAIL; } if (r != DHCP_ACK) { @@ -1129,35 +1144,6 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, assert(client->event); assert(message); - if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) { - log_dhcp_client(client, "not a DHCP message: ignoring"); - return 0; - } - - if (message->op != BOOTREPLY) { - log_dhcp_client(client, "not a BOOTREPLY message: ignoring"); - return 0; - } - - if (be32toh(message->xid) != client->xid) { - log_dhcp_client(client, "received xid (%u) does not match " - "expected (%u): ignoring", - be32toh(message->xid), client->xid); - return 0; - } - - if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) { - log_dhcp_client(client, "not an ethernet packet"); - return 0; - } - - if (memcmp(&message->chaddr[0], &client->client_id.mac_addr, - ETH_ALEN)) { - log_dhcp_client(client, "received chaddr does not match " - "expected: ignoring"); - return 0; - } - switch (client->state) { case DHCP_STATE_SELECTING: @@ -1194,25 +1180,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, case DHCP_STATE_REBINDING: r = client_handle_ack(client, message, len); - if (r == DHCP_EVENT_NO_LEASE) { - - client->timeout_resend = - sd_event_source_unref(client->timeout_resend); - - if (client->state == DHCP_STATE_REBOOTING) { - r = client_initialize(client); - if (r < 0) - goto error; - - r = client_start(client); - if (r < 0) - goto error; - - log_dhcp_client(client, "REBOOTED"); - } - - goto error; - } else if (r >= 0) { + if (r >= 0) { client->timeout_resend = sd_event_source_unref(client->timeout_resend); @@ -1231,15 +1199,51 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, if (r < 0) goto error; + r = dhcp_network_bind_udp_socket(client->lease->address, + DHCP_PORT_CLIENT); + if (r < 0) { + log_dhcp_client(client, "could not bind UDP socket"); + goto error; + } + + client->fd = r; + + client_initialize_io_events(client, client_receive_message_udp); + if (notify_event) { client_notify(client, notify_event); if (client->state == DHCP_STATE_STOPPED) return 0; } - client->receive_message = - sd_event_source_unref(client->receive_message); - client->fd = asynchronous_close(client->fd); + } else if (r == -EADDRNOTAVAIL) { + /* got a NAK, let's restart the client */ + client->timeout_resend = + sd_event_source_unref(client->timeout_resend); + + r = client_initialize(client); + if (r < 0) + goto error; + + r = client_start(client); + if (r < 0) + goto error; + + log_dhcp_client(client, "REBOOTED"); + + return 0; + } else if (r == -ENOMSG) + /* invalid message, let's ignore it */ + return 0; + + break; + + case DHCP_STATE_BOUND: + r = client_handle_forcerenew(client, message, len); + if (r >= 0) { + r = client_timeout_t1(NULL, 0, client); + if (r < 0) + goto error; } else if (r == -ENOMSG) /* invalid message, let's ignore it */ return 0; @@ -1248,7 +1252,6 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, case DHCP_STATE_INIT: case DHCP_STATE_INIT_REBOOT: - case DHCP_STATE_BOUND: break; @@ -1258,7 +1261,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, } error: - if (r < 0 || r == DHCP_EVENT_NO_LEASE) + if (r < 0) client_stop(client, r); return r; @@ -1290,8 +1293,42 @@ static int client_receive_message_udp(sd_event_source *s, int fd, log_dhcp_client(client, "could not receive message from UDP " "socket: %m"); return 0; - } else if ((size_t)len < sizeof(DHCPMessage)) + } else if ((size_t)len < sizeof(DHCPMessage)) { + log_dhcp_client(client, "too small to be a DHCP message: ignoring"); + return 0; + } + + if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) { + log_dhcp_client(client, "not a DHCP message: ignoring"); + return 0; + } + + if (message->op != BOOTREPLY) { + log_dhcp_client(client, "not a BOOTREPLY message: ignoring"); return 0; + } + + if (message->htype != ARPHRD_ETHER || message->hlen != ETHER_ADDR_LEN) { + log_dhcp_client(client, "not an ethernet packet"); + return 0; + } + + if (memcmp(&message->chaddr[0], &client->client_id.mac_addr, + ETH_ALEN)) { + log_dhcp_client(client, "received chaddr does not match " + "expected: ignoring"); + return 0; + } + + if (client->state != DHCP_STATE_BOUND && + be32toh(message->xid) != client->xid) { + /* in BOUND state, we may receive FORCERENEW with xid set by server, + so ignore the xid in this case */ + log_dhcp_client(client, "received xid (%u) does not match " + "expected (%u): ignoring", + be32toh(message->xid), client->xid); + return 0; + } return client_handle_message(client, message, len); }