dhcpv4: use iovec for leasetime/renew/rebind
authorDavid Härdeman <[email protected]>
Mon, 6 Oct 2025 12:03:34 +0000 (14:03 +0200)
committerÁlvaro Fernández Rojas <[email protected]>
Tue, 21 Oct 2025 17:05:13 +0000 (19:05 +0200)
Move some more options over to use an iovec. Note that the FIXME will be
addressed in a later patch.

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/278
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
src/dhcpv4.c
src/dhcpv4.h

index 2a5a1d0a66dae4c981fb98fa30f70203234c8beb..8a0d124f805f1f418da31116d84e7c06e8fa680b 100644 (file)
@@ -623,6 +623,9 @@ enum {
        IOV_SERVERID,
        IOV_NTP,
        IOV_NTP_ADDR,
+       IOV_LEASETIME,
+       IOV_RENEW,
+       IOV_REBIND,
        IOV_DNR,
        IOV_DNR_BODY,
        IOV_END,
@@ -672,6 +675,18 @@ void dhcpv4_handle_msg(void *src_addr, void *data, size_t len,
                .code = DHCPV4_OPT_NTPSERVER,
                .len = iface->dhcpv4_ntp_cnt * sizeof(*iface->dhcpv4_ntp),
        };
+       struct dhcpv4_option_u32 reply_leasetime = {
+               .code = DHCPV4_OPT_LEASETIME,
+               .len = sizeof(uint32_t),
+       };
+       struct dhcpv4_option_u32 reply_renew = {
+               .code = DHCPV4_OPT_RENEW,
+               .len = sizeof(uint32_t),
+       };
+       struct dhcpv4_option_u32 reply_rebind = {
+               .code = DHCPV4_OPT_REBIND,
+               .len = sizeof(uint32_t),
+       };
        struct dhcpv4_option reply_dnr = {
                .code = DHCPV4_OPT_DNR,
        };
@@ -685,6 +700,9 @@ void dhcpv4_handle_msg(void *src_addr, void *data, size_t len,
                [IOV_SERVERID]  = { &reply_serverid, sizeof(reply_serverid) },
                [IOV_NTP]       = { &reply_ntp, 0 },
                [IOV_NTP_ADDR]  = { iface->dhcpv4_ntp, 0 },
+               [IOV_LEASETIME] = { &reply_leasetime, 0 },
+               [IOV_RENEW]     = { &reply_renew, 0 },
+               [IOV_REBIND]    = { &reply_rebind, 0 },
                [IOV_DNR]       = { &reply_dnr, 0 },
                [IOV_DNR_BODY]  = { NULL, 0 },
                [IOV_END]       = { &reply_end, sizeof(reply_end) },
@@ -838,25 +856,13 @@ void dhcpv4_handle_msg(void *src_addr, void *data, size_t len,
 
        reply_opts = alloca(req_opts_len + 32);
 
-       if (a) {
-               uint32_t val;
+       reply_opts[reply_opts_len++] = DHCPV4_OPT_LEASETIME;
+       reply_opts[reply_opts_len++] = DHCPV4_OPT_RENEW;
+       reply_opts[reply_opts_len++] = DHCPV4_OPT_REBIND;
 
+       if (a) {
                reply.yiaddr.s_addr = a->addr;
 
-               val = htonl(req_leasetime);
-               dhcpv4_put(&reply, &cursor, DHCPV4_OPT_LEASETIME, 4, &val);
-               reply_opts[reply_opts_len++] = DHCPV4_OPT_LEASETIME;
-
-               if (req_leasetime != UINT32_MAX) {
-                       val = htonl(500 * req_leasetime / 1000);
-                       dhcpv4_put(&reply, &cursor, DHCPV4_OPT_RENEW, 4, &val);
-                       reply_opts[reply_opts_len++] = DHCPV4_OPT_RENEW;
-
-                       val = htonl(875 * req_leasetime / 1000);
-                       dhcpv4_put(&reply, &cursor, DHCPV4_OPT_REBIND, 4, &val);
-                       reply_opts[reply_opts_len++] = DHCPV4_OPT_REBIND;
-               }
-
                dhcpv4_put(&reply, &cursor, DHCPV4_OPT_NETMASK, 4,
                                &iface->dhcpv4_mask.s_addr);
                reply_opts[reply_opts_len++] = DHCPV4_OPT_NETMASK;
@@ -945,6 +951,27 @@ void dhcpv4_handle_msg(void *src_addr, void *data, size_t len,
                        iov[IOV_NTP_ADDR].iov_len = iface->dhcpv4_ntp_cnt * sizeof(*iface->dhcpv4_ntp);
                        break;
 
+               case DHCPV4_OPT_LEASETIME:
+                       if (!a)
+                               break;
+                       reply_leasetime.data = htonl(req_leasetime);
+                       iov[IOV_LEASETIME].iov_len = sizeof(reply_leasetime);
+                       break;
+
+               case DHCPV4_OPT_RENEW:
+                       if (!a || req_leasetime == UINT32_MAX)
+                               break;
+                       reply_renew.data = htonl(500 * req_leasetime / 1000);
+                       iov[IOV_RENEW].iov_len = sizeof(reply_renew);
+                       break;
+
+               case DHCPV4_OPT_REBIND:
+                       if (!a || req_leasetime == UINT32_MAX)
+                               break;
+                       reply_rebind.data = htonl(875 * req_leasetime / 1000);
+                       iov[IOV_REBIND].iov_len = sizeof(reply_rebind);
+                       break;
+
                case DHCPV4_OPT_DNR:
                        struct dhcpv4_dnr *dnrs;
                        size_t dnrs_len = 0;
@@ -1018,7 +1045,8 @@ void dhcpv4_handle_msg(void *src_addr, void *data, size_t len,
 
        dhcpv4_set_dest_addr(iface, reply_msg.data, req, &reply, src_addr, &dest_addr);
 
-       iov[IOV_HEADER].iov_len = PACKET_SIZE(&reply, cursor);
+       /* FIXME: check for DHCPV4_MIN_PACKET_SIZE */
+       iov[IOV_HEADER].iov_len = (size_t)(cursor - (uint8_t *)&reply);
 
        if (send_reply(iov, ARRAY_SIZE(iov), (struct sockaddr *)&dest_addr, sizeof(dest_addr), opaque) < 0)
                error("Failed to send %s to %s - %s: %m",
index 089a626ee04956308ce0e8037da6aa831076afc7..c1dc136ee0090283426a08634ef9633fb1cb2946 100644 (file)
@@ -19,6 +19,7 @@
 
 #define DHCPV4_FLAG_BROADCAST  0x8000
 
+// RFC951, §3; RFC1542, §2.1; RFC2131, §2
 #define DHCPV4_MIN_PACKET_SIZE 300
 
 #define DHCPV4_FR_MIN_DELAY    500