dhcpv4: implement router configuration option
[project/odhcpd.git] / src / dhcpv4.c
index eed634f..7b200cd 100644 (file)
@@ -20,6 +20,7 @@
 #include <stddef.h>
 #include <stdlib.h>
 #include <resolv.h>
+#include <limits.h>
 #include <net/if.h>
 #include <net/if_arp.h>
 #include <netinet/ip.h>
@@ -33,7 +34,7 @@
 
 
 static void handle_dhcpv4(void *addr, void *data, size_t len,
-               struct interface *iface);
+               struct interface *iface, void *dest_addr);
 static struct dhcpv4_assignment* dhcpv4_lease(struct interface *iface,
                enum dhcpv4_msg msg, const uint8_t *mac, struct in_addr reqaddr,
                const char *hostname);
@@ -224,7 +225,7 @@ static void dhcpv4_put(struct dhcpv4_message *msg, uint8_t **cookie,
 
 // Simple DHCPv6-server for information requests
 static void handle_dhcpv4(void *addr, void *data, size_t len,
-               struct interface *iface)
+               struct interface *iface, _unused void *dest_addr)
 {
        if (!iface->dhcpv4)
                return;
@@ -330,6 +331,10 @@ static void handle_dhcpv4(void *addr, void *data, size_t len,
                        return;
        } else if (reqmsg == DHCPV4_MSG_DISCOVER) {
                msg = DHCPV4_MSG_OFFER;
+       } else if (reqmsg == DHCPV4_MSG_REQUEST && reqaddr.s_addr &&
+                       reqaddr.s_addr != htonl(lease->addr)) {
+               msg = DHCPV4_MSG_NAK;
+               lease = NULL;
        }
 
        if (reqmsg == DHCPV4_MSG_DECLINE || reqmsg == DHCPV4_MSG_RELEASE)
@@ -379,8 +384,11 @@ static void handle_dhcpv4(void *addr, void *data, size_t len,
                                        len, search_buf);
        }
 
-       dhcpv4_put(&reply, &cookie, DHCPV4_OPT_ROUTER, 4, &ifaddr.sin_addr);
-
+       if (iface->dhcpv4_router_cnt == 0)
+               dhcpv4_put(&reply, &cookie, DHCPV4_OPT_ROUTER, 4, &ifaddr.sin_addr);
+       else
+               dhcpv4_put(&reply, &cookie, DHCPV4_OPT_ROUTER,
+                               4 * iface->dhcpv4_router_cnt, iface->dhcpv4_router);
 
 
        if (iface->dhcpv4_dns_cnt == 0)
@@ -400,7 +408,7 @@ static void handle_dhcpv4(void *addr, void *data, size_t len,
                dest.sin_addr = req->ciaddr;
                dest.sin_port = htons(DHCPV4_CLIENT_PORT);
        } else if ((ntohs(req->flags) & DHCPV4_FLAG_BROADCAST) ||
-                       req->hlen != reply.hlen) {
+                       req->hlen != reply.hlen || !reply.yiaddr.s_addr) {
                dest.sin_addr.s_addr = INADDR_BROADCAST;
                dest.sin_port = htons(DHCPV4_CLIENT_PORT);
        } else {
@@ -486,7 +494,6 @@ static struct dhcpv4_assignment* dhcpv4_lease(struct interface *iface,
                }
        }
 
-       bool update_state = false;
        if (msg == DHCPV4_MSG_DISCOVER || msg == DHCPV4_MSG_REQUEST) {
                bool assigned = !!a;
                size_t hostlen = strlen(hostname) + 1;
@@ -525,24 +532,18 @@ static struct dhcpv4_assignment* dhcpv4_lease(struct interface *iface,
                        a = NULL;
                }
 
-               if (a)
-                       update_state = true;
-
                if (assigned && a)
                        lease = a;
        } else if (msg == DHCPV4_MSG_RELEASE) {
                if (a) {
                        a->valid_until = 0;
-                       update_state = true;
                }
        } else if (msg == DHCPV4_MSG_DECLINE) {
                memset(a->hwaddr, 0, sizeof(a->hwaddr));
                a->valid_until = now + 3600; // Block address for 1h
-               update_state = true;
        }
 
-       if (update_state)
-               dhcpv6_write_statefile();
+       dhcpv6_write_statefile();
 
        return lease;
 }