chiark / gitweb /
sd-dhcp-client: add support for FORCERENEW
authorTom Gundersen <teg@jklm.no>
Thu, 15 May 2014 22:50:44 +0000 (00:50 +0200)
committerTom Gundersen <teg@jklm.no>
Mon, 28 Jul 2014 08:44:51 +0000 (10:44 +0200)
This partially implements RFC3203. Note that we are not fully compliant as we do not
support authentication.

src/libsystemd-network/dhcp-protocol.h
src/libsystemd-network/sd-dhcp-client.c

index 7c06b5a..f5119a7 100644 (file)
@@ -95,6 +95,8 @@ enum {
         DHCP_ACK                                = 5,
         DHCP_NAK                                = 6,
         DHCP_RELEASE                            = 7,
+        DHCP_INFORM                             = 8,
+        DHCP_FORCERENEW                         = 9,
 };
 
 enum {
index 68bce5e..8205ad0 100644 (file)
@@ -862,7 +862,6 @@ 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;
@@ -916,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;
@@ -1226,9 +1238,20 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
 
                 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;
+
+                break;
+
         case DHCP_STATE_INIT:
         case DHCP_STATE_INIT_REBOOT:
-        case DHCP_STATE_BOUND:
 
                 break;
 
@@ -1285,13 +1308,6 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
                 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;
@@ -1304,6 +1320,16 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
                 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);
 }