chiark / gitweb /
service: minor modernization
[elogind.git] / src / libsystemd-network / sd-dhcp-server.c
index 4a0683387534371282656c47c3782a5ee76050fa..5c32fdfffa9053c3d239cfd6ed506c5acd3ce271 100644 (file)
@@ -29,7 +29,7 @@
 #include "dhcp-server-internal.h"
 #include "dhcp-internal.h"
 
-#define DHCP_DEFAULT_LEASE_TIME         60
+#define DHCP_DEFAULT_LEASE_TIME         3600 /* one hour */
 
 int sd_dhcp_server_set_lease_pool(sd_dhcp_server *server, struct in_addr *address,
                                   size_t size) {
@@ -62,6 +62,12 @@ int sd_dhcp_server_set_address(sd_dhcp_server *server, struct in_addr *address)
         return 0;
 }
 
+bool sd_dhcp_server_is_running(sd_dhcp_server *server) {
+        assert_return(server, -EINVAL);
+
+        return !!server->receive_message;
+}
+
 sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) {
         if (server)
                 assert_se(REFCNT_INC(server->n_ref) >= 2);
@@ -105,29 +111,27 @@ static void dhcp_lease_free(DHCPLease *lease) {
         free(lease);
 }
 
-DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPLease*, dhcp_lease_free);
-#define _cleanup_dhcp_lease_free_ _cleanup_(dhcp_lease_freep)
-
 sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) {
-        if (server && REFCNT_DEC(server->n_ref) <= 0) {
-                DHCPLease *lease;
-                Iterator i;
+        DHCPLease *lease;
 
-                log_dhcp_server(server, "UNREF");
+        if (!server)
+                return NULL;
 
-                sd_dhcp_server_stop(server);
+        if (REFCNT_DEC(server->n_ref) > 0)
+                return NULL;
 
-                sd_event_unref(server->event);
+        log_dhcp_server(server, "UNREF");
 
-                HASHMAP_FOREACH(lease, server->leases_by_client_id, i) {
-                        hashmap_remove(server->leases_by_client_id, lease);
-                        dhcp_lease_free(lease);
-                }
+        sd_dhcp_server_stop(server);
 
-                hashmap_free(server->leases_by_client_id);
-                free(server->bound_leases);
-                free(server);
-        }
+        sd_event_unref(server->event);
+
+        while ((lease = hashmap_steal_first(server->leases_by_client_id)))
+                dhcp_lease_free(lease);
+        hashmap_free(server->leases_by_client_id);
+
+        free(server->bound_leases);
+        free(server);
 
         return NULL;
 }
@@ -342,9 +346,12 @@ int dhcp_server_send_packet(sd_dhcp_server *server,
         } else if (req->message->ciaddr && type != DHCP_NAK)
                 destination = req->message->ciaddr;
 
-        if (destination || requested_broadcast(req) || type == DHCP_NAK)
+        if (destination != INADDR_ANY)
                 return dhcp_server_send_udp(server, destination, &packet->dhcp,
                                             sizeof(DHCPMessage) + optoffset);
+        else if (requested_broadcast(req) || type == DHCP_NAK)
+                return dhcp_server_send_udp(server, INADDR_BROADCAST, &packet->dhcp,
+                                            sizeof(DHCPMessage) + optoffset);
         else
                 /* we cannot send UDP packet to specific MAC address when the address is
                    not yet configured, so must fall back to raw packets */
@@ -544,7 +551,7 @@ static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) {
 
         if (be32toh(requested_ip) < be32toh(server->pool_start) ||
             be32toh(requested_ip) >= be32toh(server->pool_start) +
-                                                  + server->pool_size)
+                                             + server->pool_size)
                 return -EINVAL;
 
         return be32toh(requested_ip) - be32toh(server->pool_start);
@@ -623,6 +630,15 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
 
                 break;
         }
+        case DHCP_DECLINE:
+                log_dhcp_server(server, "DECLINE (0x%x)",
+                                be32toh(req->message->xid));
+
+                /* TODO: make sure we don't offer this address again */
+
+                return 1;
+
+                break;
         case DHCP_REQUEST:
         {
                 be32_t address;
@@ -688,8 +704,10 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
                                 lease->address = req->requested_ip;
                                 lease->client_id.data = memdup(req->client_id.data,
                                                                req->client_id.length);
-                                if (!lease->client_id.data)
+                                if (!lease->client_id.data) {
+                                        free(lease);
                                         return -ENOMEM;
+                                }
                                 lease->client_id.length = req->client_id.length;
                         } else
                                 lease = existing_lease;
@@ -734,6 +752,31 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
 
                 break;
         }
+        case DHCP_RELEASE: {
+                int pool_offset;
+
+                log_dhcp_server(server, "RELEASE (0x%x)",
+                                be32toh(req->message->xid));
+
+                if (!existing_lease)
+                        return 0;
+
+                if (existing_lease->address != req->message->ciaddr)
+                        return 0;
+
+                pool_offset = get_pool_offset(server, req->message->ciaddr);
+                if (pool_offset < 0)
+                        return 0;
+
+                if (server->bound_leases[pool_offset] == existing_lease) {
+                        server->bound_leases[pool_offset] = NULL;
+                        hashmap_remove(server->leases_by_client_id, existing_lease);
+                        dhcp_lease_free(existing_lease);
+
+                        return 1;
+                } else
+                        return 0;
+        }
         }
 
         return 0;