--- /dev/null
+From ca85a28241ef87919d68d52c843b6964b7070e11 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Wed, 13 May 2015 22:33:04 +0100
+Subject: [PATCH] Allow T1 and T2 DHCPv4 options to be set.
+
+---
+ CHANGELOG | 3 +++
+ dnsmasq.conf.example | 8 ++++++
+ src/dhcp-common.c | 4 +--
+ src/rfc2131.c | 71 +++++++++++++++++++++++++++++++++++---------------
+ 4 files changed, 63 insertions(+), 23 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 94a521f..ef39a41 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -118,6 +118,9 @@ version 2.73
+ Check IPv4-mapped IPv6 addresses when --stop-rebind
+ is active. Thanks to Jordan Milne for spotting this.
+
++ Allow DHCPv4 options T1 and T2 to be set using --dhcp-option.
++ Thanks to Kevin Benton for patches and work on this.
++
+
+ version 2.72
+ Add ra-advrouter mode, for RFC-3775 mobile IPv6 support.
+diff --git a/dnsmasq.conf.example b/dnsmasq.conf.example
+index 67be99a..1ae11df 100644
+--- a/dnsmasq.conf.example
++++ b/dnsmasq.conf.example
+@@ -345,6 +345,14 @@
+ # Ask client to poll for option changes every six hours. (RFC4242)
+ #dhcp-option=option6:information-refresh-time,6h
+
++# Set option 58 client renewal time (T1). Defaults to half of the
++# lease time if not specified. (RFC2132)
++#dhcp-option=option:T1:1m
++
++# Set option 59 rebinding time (T2). Defaults to 7/8 of the
++# lease time if not specified. (RFC2132)
++#dhcp-option=option:T2:2m
++
+ # Set the NTP time server address to be the same machine as
+ # is running dnsmasq
+ #dhcp-option=42,0.0.0.0
+diff --git a/src/dhcp-common.c b/src/dhcp-common.c
+index ce11520..bc48f41 100644
+--- a/src/dhcp-common.c
++++ b/src/dhcp-common.c
+@@ -545,8 +545,8 @@ static const struct opttab_t {
+ { "parameter-request", 55, OT_INTERNAL },
+ { "message", 56, OT_INTERNAL },
+ { "max-message-size", 57, OT_INTERNAL },
+- { "T1", 58, OT_INTERNAL | OT_TIME},
+- { "T2", 59, OT_INTERNAL | OT_TIME},
++ { "T1", 58, OT_TIME},
++ { "T2", 59, OT_TIME},
+ { "vendor-class", 60, 0 },
+ { "client-id", 61, OT_INTERNAL },
+ { "nis+-domain", 64, OT_NAME },
+diff --git a/src/rfc2131.c b/src/rfc2131.c
+index 5552644..a10e499 100644
+--- a/src/rfc2131.c
++++ b/src/rfc2131.c
+@@ -52,7 +52,9 @@ static void do_options(struct dhcp_context *context,
+ int null_term, int pxearch,
+ unsigned char *uuid,
+ int vendor_class_len,
+- time_t now);
++ time_t now,
++ unsigned int lease_time,
++ unsigned short fuzz);
+
+
+ static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
+@@ -610,7 +612,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
+
+ clear_packet(mess, end);
+ do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
+- netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now);
++ netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0);
+ }
+ }
+
+@@ -1042,13 +1044,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
+ option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
+ option_put(mess, end, OPTION_LEASE_TIME, 4, time);
+ /* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
+- if (time != 0xffffffff)
+- {
+- option_put(mess, end, OPTION_T1, 4, (time/2));
+- option_put(mess, end, OPTION_T2, 4, (time*7)/8);
+- }
+ do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
+- netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
++ netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
+
+ return dhcp_packet_size(mess, agent_id, real_end);
+
+@@ -1367,15 +1364,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
+ option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
+ option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
+ option_put(mess, end, OPTION_LEASE_TIME, 4, time);
+- if (time != 0xffffffff)
+- {
+- while (fuzz > (time/16))
+- fuzz = fuzz/2;
+- option_put(mess, end, OPTION_T1, 4, (time/2) - fuzz);
+- option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz);
+- }
+ do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
+- netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
++ netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
+ }
+
+ return dhcp_packet_size(mess, agent_id, real_end);
+@@ -1440,7 +1430,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
+ }
+
+ do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
+- netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
++ netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0);
+
+ *is_inform = 1; /* handle reply differently */
+ return dhcp_packet_size(mess, agent_id, real_end);
+@@ -2137,7 +2127,9 @@ static void do_options(struct dhcp_context *context,
+ int null_term, int pxe_arch,
+ unsigned char *uuid,
+ int vendor_class_len,
+- time_t now)
++ time_t now,
++ unsigned int lease_time,
++ unsigned short fuzz)
+ {
+ struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
+ struct dhcp_boot *boot;
+@@ -2261,7 +2253,42 @@ static void do_options(struct dhcp_context *context,
+ /* rfc3011 says this doesn't need to be in the requested options list. */
+ if (subnet_addr.s_addr)
+ option_put(mess, end, OPTION_SUBNET_SELECT, INADDRSZ, ntohl(subnet_addr.s_addr));
+-
++
++ if (lease_time != 0xffffffff)
++ {
++ unsigned int t1val = lease_time/2;
++ unsigned int t2val = (lease_time*7)/8;
++ unsigned int hval;
++
++ /* If set by user, sanity check, so not longer than lease. */
++ if ((opt = option_find2(OPTION_T1)))
++ {
++ hval = ntohl(*((unsigned int *)opt->val));
++ if (hval < lease_time && hval > 2)
++ t1val = hval;
++ }
++
++ if ((opt = option_find2(OPTION_T2)))
++ {
++ hval = ntohl(*((unsigned int *)opt->val));
++ if (hval < lease_time && hval > 2)
++ t2val = hval;
++ }
++
++ /* ensure T1 is still < T2 */
++ if (t2val <= t1val)
++ t1val = t2val - 1;
++
++ while (fuzz > (t1val/8))
++ fuzz = fuzz/2;
++
++ t1val -= fuzz;
++ t2val -= fuzz;
++
++ option_put(mess, end, OPTION_T1, 4, t1val);
++ option_put(mess, end, OPTION_T2, 4, t2val);
++ }
++
+ /* replies to DHCPINFORM may not have a valid context */
+ if (context)
+ {
+@@ -2356,12 +2383,14 @@ static void do_options(struct dhcp_context *context,
+ if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))
+ continue;
+
+- /* prohibit some used-internally options */
++ /* prohibit some used-internally options. T1 and T2 already handled. */
+ if (optno == OPTION_CLIENT_FQDN ||
+ optno == OPTION_MAXMESSAGE ||
+ optno == OPTION_OVERLOAD ||
+ optno == OPTION_PAD ||
+- optno == OPTION_END)
++ optno == OPTION_END ||
++ optno == OPTION_T1 ||
++ optno == OPTION_T2)
+ continue;
+
+ if (optno == OPTION_SNAME && done_server)
+--
+1.7.10.4
+