<div dir="ltr">RFC 4039 defines DHCPv4 Rapid Commit option, which allows for obtaining an IP address and configuration information using a 2-message exchange.<div>This is particularly useful for mobile clients to quickly establish IP connectivity when changing network, e.g. from cellular to home WiFi.</div><div><div><br><div>If the DHCP client indicates Rapid Commit support in DHCPDISCOVER, the server can respond directly with DHCPACK. Rapid Commit should only be enabled on the server if it is the only server for the subnet, or if multiple servers are present they each commit a binding for all clients.</div><div><br></div><div>The patch below was tested against dhcpcd client with Rapid Commit enabled.</div><div><br></div></div></div><div>Thanks</div><div>Ashram</div><div><br></div><div><div><font face="monospace, monospace"> dnsmasq.conf.example |  8 ++++++++</font></div><div><font face="monospace, monospace"> src/dhcp-common.c    |  1 +</font></div><div><font face="monospace, monospace"> src/dhcp-protocol.h  |  1 +</font></div><div><font face="monospace, monospace"> src/dnsmasq.h        |  3 ++-</font></div><div><font face="monospace, monospace"> src/option.c         |  3 +++</font></div><div><font face="monospace, monospace"> src/rfc2131.c        | 29 +++++++++++++++++++++++++++--</font></div><div><font face="monospace, monospace"> 6 files changed, 42 insertions(+), 3 deletions(-)</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">diff --git a/dnsmasq.conf.example b/dnsmasq.conf.example</font></div><div><font face="monospace, monospace">index 574b053..7e89ef8 100644</font></div><div><font face="monospace, monospace">--- a/dnsmasq.conf.example</font></div><div><font face="monospace, monospace">+++ b/dnsmasq.conf.example</font></div><div><font face="monospace, monospace">@@ -547,6 +547,14 @@</font></div><div><font face="monospace, monospace"> # <a href="http://www.isc.org/files/auth.html">http://www.isc.org/files/auth.html</a></font></div><div><font face="monospace, monospace"> #dhcp-authoritative</font></div><div><font face="monospace, monospace"> </font></div><div><font face="monospace, monospace">+# Set the DHCP server to enable DHCPv4 Rapid Commit Option per RFC 4039.</font></div><div><font face="monospace, monospace">+# In this mode it will respond to a DHCPDISCOVER message including Rapid Commit</font></div><div><font face="monospace, monospace">+# option with a DHCPACK including Rapid Commit option and fully committed addre$</font></div><div><font face="monospace, monospace">+# and configuration information. This must only be enabled if either the server$</font></div><div><font face="monospace, monospace">+# the only server for the subnet, or multiple servers are present and they each</font></div><div><font face="monospace, monospace">+# commit a binding for all clients.</font></div><div><font face="monospace, monospace">+#rapid-commit</font></div><div><font face="monospace, monospace">+</font></div><div><font face="monospace, monospace"> # Run an executable when a DHCP lease is created or destroyed.</font></div><div><font face="monospace, monospace"> # The arguments sent to the script are "add" or "del",</font></div><div><font face="monospace, monospace"> # then the MAC address, the IP address and finally the hostname</font></div><div><font face="monospace, monospace">diff --git a/src/dhcp-common.c b/src/dhcp-common.c</font></div><div><font face="monospace, monospace">index d9719d1..8ff0f0d 100644</font></div><div><font face="monospace, monospace">--- a/src/dhcp-common.c</font></div><div><font face="monospace, monospace">+++ b/src/dhcp-common.c</font></div><div><font face="monospace, monospace">@@ -556,6 +556,7 @@ static const struct opttab_t {</font></div><div><font face="monospace, monospace">   { "nntp-server", 71, OT_ADDR_LIST }, </font></div><div><font face="monospace, monospace">   { "irc-server", 74, OT_ADDR_LIST }, </font></div><div><font face="monospace, monospace">   { "user-class", 77, 0 },</font></div><div><font face="monospace, monospace">+  { "rapid-commit", 80, 0 },</font></div><div><font face="monospace, monospace">   { "FQDN", 81, OT_INTERNAL },</font></div><div><font face="monospace, monospace">   { "agent-id", 82, OT_INTERNAL },</font></div><div><font face="monospace, monospace">   { "client-arch", 93, 2 | OT_DEC },</font></div><div><font face="monospace, monospace">diff --git a/src/dhcp-protocol.h b/src/dhcp-protocol.h</font></div><div><font face="monospace, monospace">index a4a3535..389c85e 100644</font></div><div><font face="monospace, monospace">--- a/src/dhcp-protocol.h</font></div><div><font face="monospace, monospace">+++ b/src/dhcp-protocol.h</font></div><div><font face="monospace, monospace">@@ -54,6 +54,7 @@</font></div><div><font face="monospace, monospace"> #define OPTION_SNAME             66</font></div><div><font face="monospace, monospace"> #define OPTION_FILENAME          67</font></div><div><font face="monospace, monospace"> #define OPTION_USER_CLASS        77</font></div><div><font face="monospace, monospace">+#define OPTION_RAPID_COMMIT      80</font></div><div><font face="monospace, monospace"> #define OPTION_CLIENT_FQDN       81</font></div><div><font face="monospace, monospace"> #define OPTION_AGENT_ID          82</font></div><div><font face="monospace, monospace"> #define OPTION_ARCH              93</font></div><div><font face="monospace, monospace">diff --git a/src/dnsmasq.h b/src/dnsmasq.h</font></div><div><font face="monospace, monospace">index 6773b69..30c4519 100644</font></div><div><font face="monospace, monospace">--- a/src/dnsmasq.h</font></div><div><font face="monospace, monospace">+++ b/src/dnsmasq.h</font></div><div><font face="monospace, monospace">@@ -250,7 +250,8 @@ struct event_desc {</font></div><div><font face="monospace, monospace"> #define OPT_MAC_B64        54</font></div><div><font face="monospace, monospace"> #define OPT_MAC_HEX        55</font></div><div><font face="monospace, monospace"> #define OPT_TFTP_APREF_MAC 56</font></div><div><font face="monospace, monospace">-#define OPT_LAST           57</font></div><div><font face="monospace, monospace">+#define OPT_RAPID_COMMIT   57</font></div><div><font face="monospace, monospace">+#define OPT_LAST           58</font></div><div><font face="monospace, monospace"> </font></div><div><font face="monospace, monospace"> /* extra flags for my_syslog, we use a couple of facilities since they are known </font></div><div><font face="monospace, monospace">    not to occupy the same bits as priorities, no matter how syslog.h is set up. */</font></div><div><font face="monospace, monospace">diff --git a/src/option.c b/src/option.c</font></div><div><font face="monospace, monospace">index d358d99..3691944 100644</font></div><div><font face="monospace, monospace">--- a/src/option.c</font></div><div><font face="monospace, monospace">+++ b/src/option.c</font></div><div><font face="monospace, monospace">@@ -160,6 +160,7 @@ struct myoption {</font></div><div><font face="monospace, monospace"> #define LOPT_DHCPTTL       348</font></div><div><font face="monospace, monospace"> #define LOPT_TFTP_MTU      349</font></div><div><font face="monospace, monospace"> #define LOPT_REPLY_DELAY   350</font></div><div><font face="monospace, monospace">+#define LOPT_RAPID_COMMIT  351</font></div><div><font face="monospace, monospace">  </font></div><div><font face="monospace, monospace"> #ifdef HAVE_GETOPT_LONG</font></div><div><font face="monospace, monospace"> static const struct option opts[] =  </font></div><div><font face="monospace, monospace">@@ -325,6 +326,7 @@ static const struct myoption opts[] =</font></div><div><font face="monospace, monospace">     { "script-arp", 0, 0, LOPT_SCRIPT_ARP },</font></div><div><font face="monospace, monospace">     { "dhcp-ttl", 1, 0 , LOPT_DHCPTTL },</font></div><div><font face="monospace, monospace">     { "dhcp-reply-delay", 1, 0, LOPT_REPLY_DELAY },</font></div><div><font face="monospace, monospace">+    { "rapid-commit", 0, 0, LOPT_RAPID_COMMIT },</font></div><div><font face="monospace, monospace">     { NULL, 0, 0, 0 }</font></div><div><font face="monospace, monospace">   };</font></div><div><font face="monospace, monospace"> </font></div><div><font face="monospace, monospace">@@ -497,6 +499,7 @@ static struct {</font></div><div><font face="monospace, monospace">   { LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses containing ipaddr."), NULL }, </font></div><div><font face="monospace, monospace">   { LOPT_DHCPTTL, ARG_ONE, "<ttl>", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL }, </font></div><div><font face="monospace, monospace">   { LOPT_REPLY_DELAY, ARG_ONE, "<integer>", gettext_noop("Delay DHCP replies for at least number of seconds."), NULL },</font></div><div><font face="monospace, monospace">+  { LOPT_RAPID_COMMIT, OPT_RAPID_COMMIT, NULL, gettext_noop("Enables DHCPv4 Rapid Commit option."), NULL },</font></div><div><font face="monospace, monospace">   { 0, 0, NULL, NULL, NULL }</font></div><div><font face="monospace, monospace"> }; </font></div><div><font face="monospace, monospace"> </font></div><div><font face="monospace, monospace">diff --git a/src/rfc2131.c b/src/rfc2131.c</font></div><div><font face="monospace, monospace">index c08a8ab..64b56e7 100644</font></div><div><font face="monospace, monospace">--- a/src/rfc2131.c</font></div><div><font face="monospace, monospace">+++ b/src/rfc2131.c</font></div><div><font face="monospace, monospace">@@ -1073,6 +1073,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,</font></div><div><font face="monospace, monospace"> </font></div><div><font face="monospace, monospace">       log_tags(tagif_netid, ntohl(mess->xid));</font></div><div><font face="monospace, monospace">       apply_delay(mess->xid, recvtime, tagif_netid);</font></div><div><font face="monospace, monospace">+</font></div><div><font face="monospace, monospace">+      if (!option_bool(OPT_RAPID_COMMIT) || !(opt = option_find(mess, sz, OPTION_RAPID_COMMIT, 0)))</font></div><div><font face="monospace, monospace">+<span style="white-space:pre">      </span>{</font></div><div><font face="monospace, monospace">       log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);</font></div><div><font face="monospace, monospace">       </font></div><div><font face="monospace, monospace">       time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));</font></div><div><font face="monospace, monospace">@@ -1085,8 +1088,13 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,</font></div><div><font face="monospace, monospace"> <span style="white-space:pre">              </span> netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);</font></div><div><font face="monospace, monospace">       </font></div><div><font face="monospace, monospace">       return dhcp_packet_size(mess, agent_id, real_end);</font></div><div><font face="monospace, monospace">-      </font></div><div><font face="monospace, monospace">+<span style="white-space:pre">  </span>}</font></div><div><font face="monospace, monospace">+</font></div><div><font face="monospace, monospace">+<span style="white-space:pre">      </span>/* rapid commit case falls through to send DHCPACK */</font></div><div><font face="monospace, monospace">+      __attribute__((fallthrough));</font></div><div><font face="monospace, monospace">     case DHCPREQUEST:</font></div><div><font face="monospace, monospace">+      if (!option_bool(OPT_RAPID_COMMIT) || !(opt = option_find(mess, sz, OPTION_RAPID_COMMIT, 0)))</font></div><div><font face="monospace, monospace">+<span style="white-space:pre">        </span>{</font></div><div><font face="monospace, monospace">       if (ignore || have_config(config, CONFIG_DISABLE))</font></div><div><font face="monospace, monospace"> <span style="white-space:pre"> </span>return 0;</font></div><div><font face="monospace, monospace">       if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))</font></div><div><font face="monospace, monospace">@@ -1185,6 +1193,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,</font></div><div><font face="monospace, monospace"> <span style="white-space:pre">      </span>}</font></div><div><font face="monospace, monospace">       </font></div><div><font face="monospace, monospace">       log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);</font></div><div><font face="monospace, monospace">+<span style="white-space:pre">   </span>}</font></div><div><font face="monospace, monospace">  </font></div><div><font face="monospace, monospace">       if (!message)</font></div><div><font face="monospace, monospace"> <span style="white-space:pre">    </span>{</font></div><div><font face="monospace, monospace">@@ -1256,6 +1265,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,</font></div><div><font face="monospace, monospace"> </font></div><div><font face="monospace, monospace">       if (message)</font></div><div><font face="monospace, monospace"> <span style="white-space:pre">   </span>{</font></div><div><font face="monospace, monospace">+<span style="white-space:pre">     </span>  if (!option_bool(OPT_RAPID_COMMIT) || !(opt = option_find(mess, sz, OPTION_RAPID_COMMIT, 0)))</font></div><div><font face="monospace, monospace">+<span style="white-space:pre">      </span>  {</font></div><div><font face="monospace, monospace"> <span style="white-space:pre"> </span>  log_packet("DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, NULL, message, mess->xid);</font></div><div><font face="monospace, monospace"> <span style="white-space:pre">   </span>  </font></div><div><font face="monospace, monospace"> <span style="white-space:pre"> </span>  mess->yiaddr.s_addr = 0;</font></div><div><font face="monospace, monospace">@@ -1271,6 +1282,12 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,</font></div><div><font face="monospace, monospace"> <span style="white-space:pre">  </span>      mess->flags |= htons(0x8000); /* broadcast */</font></div><div><font face="monospace, monospace"> <span style="white-space:pre">    </span>      mess->ciaddr.s_addr = 0;</font></div><div><font face="monospace, monospace"> <span style="white-space:pre"> </span>    }</font></div><div><font face="monospace, monospace">+<span style="white-space:pre">       </span>  }</font></div><div><font face="monospace, monospace">+<span style="white-space:pre">  </span>  else</font></div><div><font face="monospace, monospace">+<span style="white-space:pre">       </span>  {</font></div><div><font face="monospace, monospace">+<span style="white-space:pre">          </span>/* rapid commit case: lease allocate failed but don't send DHCPNAK */</font></div><div><font face="monospace, monospace">+<span style="white-space:pre">             </span>return 0;</font></div><div><font face="monospace, monospace">+<span style="white-space:pre">     </span>  }</font></div><div><font face="monospace, monospace"> <span style="white-space:pre"> </span>}</font></div><div><font face="monospace, monospace">       else</font></div><div><font face="monospace, monospace"> <span style="white-space:pre">       </span>{</font></div><div><font face="monospace, monospace">@@ -1415,7 +1432,15 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,</font></div><div><font face="monospace, monospace"> </font></div><div><font face="monospace, monospace"> <span style="white-space:pre">       </span>  log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);  </font></div><div><font face="monospace, monospace"> <span style="white-space:pre">      </span>  </font></div><div><font face="monospace, monospace">-<span style="white-space:pre">  </span>  clear_packet(mess, end);</font></div><div><font face="monospace, monospace">+<span style="white-space:pre">   </span>  if (option_bool(OPT_RAPID_COMMIT) && (opt = option_find(mess, sz, OPTION_RAPID_COMMIT, 0)))</font></div><div><font face="monospace, monospace">+<span style="white-space:pre">        </span>  {</font></div><div><font face="monospace, monospace">+<span style="white-space:pre">          </span>clear_packet(mess, end);</font></div><div><font face="monospace, monospace">+<span style="white-space:pre">              </span>option_put(mess, end, OPTION_RAPID_COMMIT, 0, 0);</font></div><div><font face="monospace, monospace">+<span style="white-space:pre">     </span>  }</font></div><div><font face="monospace, monospace">+<span style="white-space:pre">  </span>  else</font></div><div><font face="monospace, monospace">+<span style="white-space:pre">       </span>  {</font></div><div><font face="monospace, monospace">+<span style="white-space:pre">  </span>  <span style="white-space:pre">  </span>clear_packet(mess, end);</font></div><div><font face="monospace, monospace">+<span style="white-space:pre">      </span>  }</font></div><div><font face="monospace, monospace"> <span style="white-space:pre"> </span>  option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);</font></div><div><font face="monospace, monospace"> <span style="white-space:pre">   </span>  option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));</font></div><div><font face="monospace, monospace"> <span style="white-space:pre">  </span>  option_put(mess, end, OPTION_LEASE_TIME, 4, time);</font></div></div><div><br></div></div>