• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/odhcpd/src/dhcpv4.c

  1 /**
  2  * Copyright (C) 2012-2013 Steven Barth <steven@midlink.org>
  3  * Copyright (C) 2016 Hans Dedecker <dedeckeh@gmail.com>
  4  *
  5  * This program is free software; you can redistribute it and/or modify
  6  * it under the terms of the GNU General Public License v2 as published by
  7  * the Free Software Foundation.
  8  *
  9  * This program is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 12  * GNU General Public License for more details.
 13  *
 14  */
 15 
 16 #include <time.h>
 17 #include <errno.h>
 18 #include <fcntl.h>
 19 #include <unistd.h>
 20 #include <stddef.h>
 21 #include <stdlib.h>
 22 #include <limits.h>
 23 #include <alloca.h>
 24 #include <net/if.h>
 25 #include <net/if_arp.h>
 26 #include <netinet/ip.h>
 27 #include <netinet/udp.h>
 28 #include <sys/ioctl.h>
 29 #include <sys/timerfd.h>
 30 #include <arpa/inet.h>
 31 #include <linux/filter.h>
 32 
 33 #include <libubox/md5.h>
 34 
 35 #include "odhcpd.h"
 36 #include "dhcpv4.h"
 37 #include "dhcpv6.h"
 38 #include "statefiles.h"
 39 
 40 static uint32_t serial = 0;
 41 
 42 struct odhcpd_ref_ip {
 43         struct list_head head;
 44         int ref_cnt;
 45         struct odhcpd_ipaddr addr;
 46 };
 47 
 48 static void inc_ref_cnt_ip(struct odhcpd_ref_ip **ptr, struct odhcpd_ref_ip *ip)
 49 {
 50         *ptr = ip;
 51         ip->ref_cnt++;
 52 }
 53 
 54 static void decr_ref_cnt_ip(struct odhcpd_ref_ip **ptr, struct interface *iface)
 55 {
 56         struct odhcpd_ref_ip *ip = *ptr;
 57 
 58         if (--ip->ref_cnt == 0) {
 59                 netlink_setup_addr(&ip->addr, iface->ifindex, false, false);
 60 
 61                 list_del(&ip->head);
 62                 free(ip);
 63         }
 64 
 65         *ptr = NULL;
 66 }
 67 
 68 static bool addr_is_fr_ip(struct interface *iface, struct in_addr *addr)
 69 {
 70         struct odhcpd_ref_ip *p;
 71 
 72         list_for_each_entry(p, &iface->dhcpv4_fr_ips, head) {
 73                 if (addr->s_addr == p->addr.addr.in.s_addr)
 74                         return true;
 75         }
 76 
 77         return false;
 78 }
 79 
 80 static bool leases_require_fr(struct interface *iface, struct odhcpd_ipaddr *oaddr)
 81 {
 82         struct dhcpv4_lease *lease = NULL;
 83         struct odhcpd_ref_ip *fr_ip = NULL;
 84 
 85         avl_for_each_element(&iface->dhcpv4_leases, lease, iface_avl) {
 86                 if (!lease->accept_fr_nonce && !iface->dhcpv4_forcereconf)
 87                         continue;
 88 
 89                 if (lease->fr_ip)
 90                         continue;
 91 
 92                 if ((lease->ipv4.s_addr & oaddr->netmask) != (oaddr->addr.in.s_addr & oaddr->netmask))
 93                         continue;
 94 
 95                 if (!fr_ip) {
 96                         fr_ip = calloc(1, sizeof(*fr_ip));
 97                         if (!fr_ip)
 98                                 break;
 99 
100                         list_add(&fr_ip->head, &iface->dhcpv4_fr_ips);
101                         fr_ip->addr = *oaddr;
102                 }
103                 inc_ref_cnt_ip(&lease->fr_ip, fr_ip);
104         }
105 
106         return fr_ip ? true : false;
107 }
108 
109 static const char *dhcpv4_msg_to_string(uint8_t req_msg)
110 {
111         static const char *dhcpv4_msg_names[] = {
112                 [DHCPV4_MSG_DISCOVER]           = "DHCPV4_MSG_DISCOVER",
113                 [DHCPV4_MSG_OFFER]              = "DHCPV4_MSG_OFFER",
114                 [DHCPV4_MSG_REQUEST]            = "DHCPV4_MSG_REQUEST",
115                 [DHCPV4_MSG_DECLINE]            = "DHCPV4_MSG_DECLINE",
116                 [DHCPV4_MSG_ACK]                = "DHCPV4_MSG_ACK",
117                 [DHCPV4_MSG_NAK]                = "DHCPV4_MSG_NAK",
118                 [DHCPV4_MSG_RELEASE]            = "DHCPV4_MSG_RELEASE",
119                 [DHCPV4_MSG_INFORM]             = "DHCPV4_MSG_INFORM",
120                 [DHCPV4_MSG_FORCERENEW]         = "DHCPV4_MSG_FORCERENEW",
121                 [DHCPV4_MSG_LEASEQUERY]         = "DHCPV4_MSG_LEASEQUERY",
122                 [DHCPV4_MSG_LEASEUNASSIGNED]    = "DHCPV4_MSG_LEASEUNASSIGNED",
123                 [DHCPV4_MSG_LEASEUNKNOWN]       = "DHCPV4_MSG_LEASEUNKNOWN",
124                 [DHCPV4_MSG_LEASEACTIVE]        = "DHCPV4_MSG_LEASEACTIVE",
125                 [DHCPV4_MSG_BULKLEASEQUERY]     = "DHCPV4_MSG_BULKLEASEQUERY",
126                 [DHCPV4_MSG_LEASEQUERYDONE]     = "DHCPV4_MSG_LEASEQUERYDONE",
127                 [DHCPV4_MSG_ACTIVELEASEQUERY]   = "DHCPV4_MSG_ACTIVELEASEQUERY",
128                 [DHCPV4_MSG_LEASEQUERYSTATUS]   = "DHCPV4_MSG_LEASEQUERYSTATUS",
129                 [DHCPV4_MSG_TLS]                = "DHCPV4_MSG_TLS",
130         };
131 
132         if (req_msg >= ARRAY_SIZE(dhcpv4_msg_names))
133                 return "UNKNOWN";
134         return dhcpv4_msg_names[req_msg];
135 }
136 
137 static ssize_t dhcpv4_send_reply(struct iovec *iov, size_t iov_len,
138                                  struct sockaddr *dest, socklen_t dest_len,
139                                  void *opaque)
140 {
141         int *sock = opaque;
142         struct msghdr msg = {
143                 .msg_name = dest,
144                 .msg_namelen = dest_len,
145                 .msg_iov = iov,
146                 .msg_iovlen = iov_len,
147         };
148 
149         return sendmsg(*sock, &msg, MSG_DONTWAIT);
150 }
151 
152 static void dhcpv4_add_padding(struct iovec *iov, size_t iovlen)
153 {
154         // Theoretical max padding = vendor-specific area, RFC951, §3
155         static uint8_t padding[64] = { 0 };
156         size_t len = 0;
157 
158         if (!iov || !iovlen)
159                 return;
160 
161         iov[iovlen - 1].iov_base = padding;
162         iov[iovlen - 1].iov_len = 0;
163 
164         for (size_t i = 0; i < iovlen; i++)
165                 len += iov[i].iov_len;
166 
167         if (len < DHCPV4_MIN_PACKET_SIZE)
168                 iov[iovlen - 1].iov_len = DHCPV4_MIN_PACKET_SIZE - len;
169 }
170 
171 enum {
172         IOV_FR_HEADER = 0,
173         IOV_FR_MESSAGE,
174         IOV_FR_AUTH,
175         IOV_FR_AUTH_BODY,
176         IOV_FR_SERVERID,
177         IOV_FR_END,
178         IOV_FR_PADDING,
179         IOV_FR_TOTAL
180 };
181 
182 static void dhcpv4_fr_send(struct dhcpv4_lease *lease)
183 {
184         struct dhcpv4_message fr = {
185                 .op = DHCPV4_OP_BOOTREPLY,
186                 .htype = ARPHRD_ETHER,
187                 .hlen = ETH_ALEN,
188                 .hops = 0,
189                 .xid = 0,
190                 .secs = 0,
191                 .flags = 0,
192                 .ciaddr = { INADDR_ANY },
193                 .yiaddr = { INADDR_ANY },
194                 .siaddr = { INADDR_ANY },
195                 .giaddr = { INADDR_ANY },
196                 .chaddr = { 0 },
197                 .sname = { 0 },
198                 .file = { 0 },
199                 .cookie = htonl(DHCPV4_MAGIC_COOKIE),
200         };
201         struct dhcpv4_option_u8 fr_msg = {
202                 .code = DHCPV4_OPT_MESSAGE,
203                 .len = sizeof(uint8_t),
204                 .data = DHCPV4_MSG_FORCERENEW,
205         };
206         struct dhcpv4_auth_forcerenew fr_auth_body = {
207                 .protocol = DHCPV4_AUTH_PROTO_RKAP,
208                 .algorithm = DHCPV4_AUTH_ALG_HMAC_MD5,
209                 .rdm = DHCPV4_AUTH_RDM_MONOTONIC,
210                 .type = DHCPV4_AUTH_RKAP_AI_TYPE_MD5_DIGEST,
211                 .key = { 0 },
212         };
213         struct dhcpv4_option fr_auth = {
214                 .code = DHCPV4_OPT_AUTHENTICATION,
215                 .len = sizeof(fr_auth_body),
216         };
217         struct dhcpv4_option_u32 fr_serverid = {
218                 .code = DHCPV4_OPT_SERVERID,
219                 .len = sizeof(struct in_addr),
220                 .data = lease->fr_ip->addr.addr.in.s_addr,
221         };
222         uint8_t fr_end = DHCPV4_OPT_END;
223 
224         struct iovec iov[IOV_FR_TOTAL] = {
225                 [IOV_FR_HEADER]         = { &fr, sizeof(fr) },
226                 [IOV_FR_MESSAGE]        = { &fr_msg, sizeof(fr_msg) },
227                 [IOV_FR_AUTH]           = { &fr_auth, 0 },
228                 [IOV_FR_AUTH_BODY]      = { &fr_auth_body, 0 },
229                 [IOV_FR_SERVERID]       = { &fr_serverid, 0 },
230                 [IOV_FR_END]            = { &fr_end, sizeof(fr_end) },
231                 [IOV_FR_PADDING]        = { NULL, 0 },
232         };
233 
234         struct sockaddr_in dest = {
235                 .sin_family = AF_INET,
236                 .sin_port = htons(DHCPV4_CLIENT_PORT),
237                 .sin_addr = lease->ipv4,
238         };
239 
240         odhcpd_urandom(&fr.xid, sizeof(fr.xid));
241         memcpy(fr.chaddr, lease->hwaddr, fr.hlen);
242 
243         if (lease->accept_fr_nonce) {
244                 uint8_t secretbytes[64] = { 0 };
245                 md5_ctx_t md5;
246 
247                 fr_auth_body.replay[0] = htonl(time(NULL));
248                 fr_auth_body.replay[1] = htonl(++serial);
249                 iov[IOV_FR_AUTH].iov_len = sizeof(fr_auth);
250                 iov[IOV_FR_AUTH_BODY].iov_len = sizeof(fr_auth_body);
251                 dhcpv4_add_padding(iov, ARRAY_SIZE(iov));
252 
253                 memcpy(secretbytes, lease->key, sizeof(lease->key));
254                 for (size_t i = 0; i < sizeof(secretbytes); ++i)
255                         secretbytes[i] ^= 0x36;
256 
257                 md5_begin(&md5);
258                 md5_hash(secretbytes, sizeof(secretbytes), &md5);
259                 for (size_t i = 0; i < ARRAY_SIZE(iov); i++)
260                         md5_hash(iov[i].iov_base, iov[i].iov_len, &md5);
261                 md5_end(fr_auth_body.key, &md5);
262 
263                 for (size_t i = 0; i < sizeof(secretbytes); ++i) {
264                         secretbytes[i] ^= 0x36;
265                         secretbytes[i] ^= 0x5c;
266                 }
267 
268                 md5_begin(&md5);
269                 md5_hash(secretbytes, sizeof(secretbytes), &md5);
270                 md5_hash(fr_auth_body.key, sizeof(fr_auth_body.key), &md5);
271                 md5_end(fr_auth_body.key, &md5);
272         } else {
273                 iov[IOV_FR_SERVERID].iov_len = sizeof(fr_serverid);
274                 dhcpv4_add_padding(iov, ARRAY_SIZE(iov));
275         }
276 
277         if (dhcpv4_send_reply(iov, ARRAY_SIZE(iov), (struct sockaddr *)&dest, sizeof(dest),
278                               &lease->iface->dhcpv4_event.uloop.fd) < 0) {
279                 char ipv4_str[INET_ADDRSTRLEN];
280 
281                 error("Failed to send %s to %s - %s: %m", dhcpv4_msg_to_string(fr_msg.data),
282                       odhcpd_print_mac(lease->hwaddr, sizeof(lease->hwaddr)),
283                       inet_ntop(AF_INET, &dest, ipv4_str, sizeof(ipv4_str)));
284         } else {
285                 char ipv4_str[INET_ADDRSTRLEN];
286 
287                 debug("Sent %s to %s - %s", dhcpv4_msg_to_string(fr_msg.data),
288                       odhcpd_print_mac(lease->hwaddr, sizeof(lease->hwaddr)),
289                       inet_ntop(AF_INET, &dest, ipv4_str, sizeof(ipv4_str)));
290         }
291 }
292 
293 static void dhcpv4_fr_stop(struct dhcpv4_lease *lease)
294 {
295         uloop_timeout_cancel(&lease->fr_timer);
296         decr_ref_cnt_ip(&lease->fr_ip, lease->iface);
297         lease->fr_cnt = 0;
298         lease->fr_timer.cb = NULL;
299 }
300 
301 static void dhcpv4_fr_timer(struct uloop_timeout *event)
302 {
303         struct dhcpv4_lease *lease = container_of(event, struct dhcpv4_lease, fr_timer);
304 
305         if (lease->fr_cnt > 0 && lease->fr_cnt < 8) {
306                 dhcpv4_fr_send(lease);
307                 uloop_timeout_set(&lease->fr_timer, 1000 << lease->fr_cnt);
308                 lease->fr_cnt++;
309         } else
310                 dhcpv4_fr_stop(lease);
311 }
312 
313 static void dhcpv4_fr_start(struct dhcpv4_lease *lease)
314 {
315         uloop_timeout_set(&lease->fr_timer, 1000 << lease->fr_cnt);
316         lease->fr_timer.cb = dhcpv4_fr_timer;
317         lease->fr_cnt++;
318 
319         dhcpv4_fr_send(lease);
320 }
321 
322 static void dhcpv4_fr_rand_delay(struct dhcpv4_lease *lease);
323 
324 static void dhcpv4_fr_delay_timer(struct uloop_timeout *event)
325 {
326         struct dhcpv4_lease *lease = container_of(event, struct dhcpv4_lease, fr_timer);
327         struct interface *iface = lease->iface;
328 
329         (iface->dhcpv4_event.uloop.fd == -1 ? dhcpv4_fr_rand_delay(lease) : dhcpv4_fr_start(lease));
330 }
331 
332 static void dhcpv4_fr_rand_delay(struct dhcpv4_lease *lease)
333 {
334         int msecs;
335 
336         odhcpd_urandom(&msecs, sizeof(msecs));
337 
338         msecs = abs(msecs) % DHCPV4_FR_MAX_FUZZ + DHCPV4_FR_MIN_DELAY;
339 
340         uloop_timeout_set(&lease->fr_timer, msecs);
341         lease->fr_timer.cb = dhcpv4_fr_delay_timer;
342 }
343 
344 void dhcpv4_free_lease(struct dhcpv4_lease *lease)
345 {
346         if (!lease)
347                 return;
348 
349         if (lease->fr_ip)
350                 dhcpv4_fr_stop(lease);
351 
352         if (lease->iface) {
353                 lease->iface->update_statefile = true;
354                 avl_delete(&lease->iface->dhcpv4_leases, &lease->iface_avl);
355         }
356 
357         if (lease->lease_cfg)
358                 lease->lease_cfg->dhcpv4_lease = NULL;
359 
360         free(lease->hostname);
361         free(lease);
362 }
363 
364 static struct dhcpv4_lease *
365 dhcpv4_alloc_lease(struct interface *iface, const uint8_t *hwaddr,
366                    size_t hwaddr_len, const uint8_t *duid, size_t duid_len,
367                    uint32_t iaid)
368 {
369         struct dhcpv4_lease *lease;
370 
371         if (!iface || !hwaddr || hwaddr_len == 0 || hwaddr_len > sizeof(lease->hwaddr))
372                 return NULL;
373 
374         lease = calloc(1, sizeof(*lease) + duid_len);
375         if (!lease)
376                 return NULL;
377 
378         lease->iface_avl.key = &lease->ipv4;
379         lease->hwaddr_len = hwaddr_len;
380         memcpy(lease->hwaddr, hwaddr, hwaddr_len);
381         if (duid_len > 0) {
382                 lease->duid_len = duid_len;
383                 memcpy(lease->duid, duid, duid_len);
384                 lease->iaid = iaid;
385         }
386         lease->iface = iface;
387 
388         return lease;
389 }
390 
391 static bool dhcpv4_insert_lease(struct avl_tree *avl, struct dhcpv4_lease *lease,
392                                 struct in_addr addr)
393 {
394         lease->ipv4 = addr;
395         if (!avl_insert(avl, &lease->iface_avl))
396                 return true;
397         else
398                 return false;
399 }
400 
401 static bool dhcpv4_assign_random(struct interface *iface,
402                                  struct dhcpv4_lease *lease)
403 {
404         uint32_t pool_start = ntohl(iface->dhcpv4_start_ip.s_addr);
405         uint32_t pool_end = ntohl(iface->dhcpv4_end_ip.s_addr);
406         uint32_t pool_size = pool_end - pool_start + 1;
407         unsigned short xsubi[3];
408         uint32_t try;
409 
410         /* Pick a random starting point, using hwaddr as seed... */
411         memcpy(xsubi, lease->hwaddr, sizeof(xsubi));
412         try = pool_start + nrand48(xsubi) % pool_size;
413 
414         /* ...then loop over the whole pool from that point */
415         for (uint32_t i = 0; i < pool_size; i++, try++) {
416                 struct in_addr in_try;
417 
418                 if (try > pool_end)
419                         try = pool_start;
420 
421                 in_try.s_addr = htonl(try);
422 
423                 if (config_find_lease_cfg_by_ipv4(in_try))
424                         continue;
425 
426                 if (dhcpv4_insert_lease(&iface->dhcpv4_leases, lease, in_try))
427                         return true;
428         }
429 
430         return false;
431 }
432 
433 static bool dhcpv4_assign(struct interface *iface, struct dhcpv4_lease *lease,
434                           struct in_addr req_addr)
435 {
436         uint32_t pool_start = ntohl(iface->dhcpv4_start_ip.s_addr);
437         uint32_t pool_end = ntohl(iface->dhcpv4_end_ip.s_addr);
438         char ipv4_str[INET_ADDRSTRLEN];
439         const char *addr_type = NULL;
440 
441         /* Preconfigured IP address by static lease */
442         if (lease->ipv4.s_addr) {
443                 if (!dhcpv4_insert_lease(&iface->dhcpv4_leases, lease, lease->ipv4)) {
444                         error("The static IP address %s is already assigned on %s",
445                               inet_ntop(AF_INET, &lease->ipv4, ipv4_str, sizeof(ipv4_str)),
446                               iface->name);
447                         return false;
448                 }
449 
450                 addr_type = "static";
451                 goto out;
452         }
453 
454         if (iface->no_dynamic_dhcp) {
455                 debug("Dynamic leases disabled, not assigning lease");
456                 return false;
457         }
458 
459         if (req_addr.s_addr != INADDR_ANY) {
460                 /* The client asked for a specific address, let's try... */
461                 if (ntohl(req_addr.s_addr) < pool_start || ntohl(req_addr.s_addr) > pool_end) {
462                         debug("The requested IP address %s is outside the pool on %s",
463                               inet_ntop(AF_INET, &req_addr, ipv4_str, sizeof(ipv4_str)),
464                               iface->ifname);
465                 } else if (config_find_lease_cfg_by_ipv4(req_addr)) {
466                         debug("The requested IP address %s is statically assigned on %s",
467                               inet_ntop(AF_INET, &req_addr, ipv4_str, sizeof(ipv4_str)),
468                               iface->ifname);
469                 } else if (!dhcpv4_insert_lease(&iface->dhcpv4_leases, lease, req_addr)) {
470                         debug("The requested IP address %s is already assigned on %s",
471                               inet_ntop(AF_INET, &req_addr, ipv4_str, sizeof(ipv4_str)),
472                               iface->ifname);
473                 } else {
474                         addr_type = "requested";
475                         goto out;
476                 }
477         }
478 
479         if (!dhcpv4_assign_random(iface, lease)) {
480                 warn("Can't assign any IP address, DHCP pool exhausted on %s", iface->name);
481                 return false;
482         }
483         addr_type = "random";
484 
485 out:
486         debug("Assigned %s IP address %s on %s", addr_type,
487               inet_ntop(AF_INET, &lease->ipv4, ipv4_str, sizeof(ipv4_str)),
488               iface->ifname);
489         iface->update_statefile = true;
490         return true;
491 }
492 
493 static struct dhcpv4_lease *find_lease_by_hwaddr(struct interface *iface, const uint8_t *hwaddr)
494 {
495         struct dhcpv4_lease *lease;
496 
497         avl_for_each_element(&iface->dhcpv4_leases, lease, iface_avl)
498                 if (!memcmp(lease->hwaddr, hwaddr, ETH_ALEN))
499                         return lease;
500 
501         return NULL;
502 }
503 
504 static struct dhcpv4_lease *
505 find_lease_by_duid_iaid(struct interface *iface, const uint8_t *duid,
506                         size_t duid_len, uint32_t iaid)
507 {
508         struct dhcpv4_lease *lease;
509 
510         avl_for_each_element(&iface->dhcpv4_leases, lease, iface_avl) {
511                 if (lease->duid_len != duid_len || lease->iaid != iaid)
512                         continue;
513                 if (!memcmp(lease->duid, duid, duid_len))
514                         return lease;
515         }
516 
517         return NULL;
518 }
519 
520 static struct dhcpv4_lease *
521 dhcpv4_lease(struct interface *iface, enum dhcpv4_msg req_msg, const uint8_t *req_mac,
522              const uint8_t *clid, size_t clid_len, const struct in_addr req_addr,
523              uint32_t *req_leasetime, const char *req_hostname, const size_t
524              req_hostname_len, const bool req_accept_fr, bool *reply_incl_fr,
525              uint32_t *fr_serverid)
526 {
527         struct dhcpv4_lease *lease = NULL;
528         struct lease_cfg *lease_cfg = NULL;
529         const uint8_t *duid = NULL;
530         size_t duid_len = 0;
531         uint32_t iaid = 0;
532         time_t now = odhcpd_time();
533 
534         // RFC4361, §6.1, §6.3 - MUST use clid if provided, MAY use chaddr
535         if (clid && clid_len > (1 + sizeof(iaid) + DUID_MIN_LEN) &&
536             clid[0] == DHCPV4_CLIENTID_TYPE_DUID_IAID &&
537             clid_len <= (1 + sizeof(iaid) + DUID_MAX_LEN)) {
538                 memcpy(&iaid, &clid[1], sizeof(uint32_t));
539                 iaid = ntohl(iaid);
540 
541                 duid = &clid[1 + sizeof(iaid)];
542                 duid_len = clid_len - (1 + sizeof(iaid));
543 
544                 lease = find_lease_by_duid_iaid(iface, duid, duid_len, iaid);
545                 lease_cfg = config_find_lease_cfg_by_duid_and_iaid(duid, duid_len, iaid);
546         }
547 
548         if (!lease)
549                 lease = find_lease_by_hwaddr(iface, req_mac);
550 
551         if (!lease_cfg)
552                 lease_cfg = config_find_lease_cfg_by_mac(req_mac);
553 
554         if (lease_cfg && lease_cfg->ignore4)
555                 return NULL;
556 
557         /*
558          * If we found a static lease cfg, but no old assignment for this
559          * hwaddr, we need to clear out any old assignments given to other
560          * hwaddrs in order to take over the IP address.
561          */
562         if (lease_cfg && !lease && (req_msg == DHCPV4_MSG_DISCOVER || req_msg == DHCPV4_MSG_REQUEST))
563                 dhcpv4_free_lease(lease_cfg->dhcpv4_lease);
564 
565         if (lease_cfg && lease && lease->lease_cfg != lease_cfg) {
566                 dhcpv4_free_lease(lease);
567                 lease = NULL;
568         }
569 
570         if (lease && lease->bound && lease->fr_ip) {
571                 *fr_serverid = lease->fr_ip->addr.addr.in.s_addr;
572                 dhcpv4_fr_stop(lease);
573         }
574 
575         switch (req_msg) {
576         case DHCPV4_MSG_RELEASE:
577                 if (!lease)
578                         return NULL;
579 
580                 ubus_bcast_dhcpv4_event("dhcp.release4", iface->ifname, lease);
581                 dhcpv4_free_lease(lease);
582                 lease = NULL;
583                 break;
584 
585         case DHCPV4_MSG_DECLINE:
586                 if (!lease)
587                         return NULL;
588 
589                 lease->bound = false;
590 
591                 if (!lease->lease_cfg || lease->lease_cfg->ipv4.s_addr != lease->ipv4.s_addr) {
592                         memset(lease->hwaddr, 0, sizeof(lease->hwaddr));
593                         lease->valid_until = now + 3600; /* Block address for 1h */
594                 } else {
595                         lease->valid_until = now - 1;
596                 }
597                 break;
598 
599         case DHCPV4_MSG_DISCOVER:
600         case DHCPV4_MSG_REQUEST:
601                 if (!lease && iface->no_dynamic_dhcp && !lease_cfg)
602                         return NULL;
603 
604                 /* Old lease, but with an address that is out-of-scope? */
605                 if (lease && !lease->lease_cfg &&
606                     ((lease->ipv4.s_addr & iface->dhcpv4_own_ip.netmask) !=
607                      (iface->dhcpv4_start_ip.s_addr & iface->dhcpv4_own_ip.netmask))) {
608                         /* Try to reassign to an address that is in-scope */
609                         avl_delete(&iface->dhcpv4_leases, &lease->iface_avl);
610                         lease->ipv4.s_addr = INADDR_ANY;
611                         if (!dhcpv4_assign(iface, lease, req_addr)) {
612                                 dhcpv4_free_lease(lease);
613                                 lease = NULL;
614                                 break;
615                         }
616                 }
617 
618                 if (!lease) {
619                         /* Create new binding */
620                         lease = dhcpv4_alloc_lease(iface, req_mac, ETH_ALEN, duid, duid_len, iaid);
621                         if (!lease) {
622                                 warn("Failed to allocate memory for DHCPv4 lease on interface %s", iface->ifname);
623                                 return NULL;
624                         }
625 
626                         /* static lease => infinite (0), else a placeholder */
627                         lease->valid_until = lease_cfg ? 0 : now;
628                         lease->ipv4.s_addr = lease_cfg ? lease_cfg->ipv4.s_addr : INADDR_ANY;
629 
630                         if (!dhcpv4_assign(iface, lease, req_addr)) {
631                                 dhcpv4_free_lease(lease);
632                                 return NULL;
633                         }
634 
635                         if (lease_cfg) {
636                                 if (lease_cfg->hostname) {
637                                         lease->hostname = strdup(lease_cfg->hostname);
638                                         lease->hostname_valid = true;
639                                 }
640 
641                                 lease_cfg->dhcpv4_lease = lease;
642                                 lease->lease_cfg = lease_cfg;
643                         }
644                 }
645 
646                 /* See if we need to clamp the requested leasetime */
647                 uint32_t max_leasetime;
648                 if (lease->lease_cfg && lease->lease_cfg->leasetime)
649                         max_leasetime = lease->lease_cfg->leasetime;
650                 else
651                         max_leasetime = iface->dhcp_leasetime;
652 
653                 if ((*req_leasetime == 0) || (max_leasetime < *req_leasetime))
654                         *req_leasetime = max_leasetime;
655 
656                 if (req_msg == DHCPV4_MSG_DISCOVER) {
657                         lease->bound = false;
658                         *reply_incl_fr = req_accept_fr;
659                         lease->valid_until = now;
660                         break;
661                 }
662 
663                 if (req_hostname_len > 0 && (!lease->lease_cfg || !lease->lease_cfg->hostname)) {
664                         char *new_name = realloc(lease->hostname, req_hostname_len + 1);
665                         if (new_name) {
666                                 lease->hostname = new_name;
667                                 memcpy(lease->hostname, req_hostname, req_hostname_len);
668                                 lease->hostname[req_hostname_len] = 0;
669                                 lease->hostname_valid = odhcpd_hostname_valid(lease->hostname);
670                         }
671                 }
672 
673                 *reply_incl_fr = false;
674                 if (!lease->bound) {
675                         /* This is the client's first request for the address */
676                         if (req_accept_fr) {
677                                 lease->accept_fr_nonce = true;
678                                 *reply_incl_fr = true;
679                                 odhcpd_urandom(lease->key, sizeof(lease->key));
680                         }
681                         lease->bound = true;
682                 }
683 
684                 if (*req_leasetime == UINT32_MAX)
685                         lease->valid_until = 0;
686                 else
687                         lease->valid_until = (time_t)(now + *req_leasetime);
688                 break;
689 
690         default:
691                 return NULL;
692         }
693 
694         iface->update_statefile = true;
695         return lease;
696 }
697 
698 static void dhcpv4_set_dest_addr(const struct interface *iface,
699                                  uint8_t reply_msg,
700                                  const struct dhcpv4_message *req,
701                                  const struct dhcpv4_message *reply,
702                                  const struct sockaddr_in *src,
703                                  struct sockaddr_in *dest)
704 {
705         *dest = *src;
706 
707         //struct sockaddr_in dest = *((struct sockaddr_in*)addr);
708         if (req->giaddr.s_addr) {
709                 /*
710                  * relay agent is configured, send reply to the agent
711                  */
712                 dest->sin_addr = req->giaddr;
713                 dest->sin_port = htons(DHCPV4_SERVER_PORT);
714 
715         } else if (req->ciaddr.s_addr && req->ciaddr.s_addr != dest->sin_addr.s_addr) {
716                 /*
717                  * client has existing configuration (ciaddr is set) AND this
718                  * address is not the address it used for the dhcp message
719                  */
720                 dest->sin_addr = req->ciaddr;
721                 dest->sin_port = htons(DHCPV4_CLIENT_PORT);
722 
723         } else if (ntohs(req->flags) & DHCPV4_FLAG_BROADCAST ||
724                    req->hlen != reply->hlen || !reply->yiaddr.s_addr) {
725                 /*
726                  * client requests a broadcast reply OR we can't offer an IP
727                  */
728                 dest->sin_addr.s_addr = INADDR_BROADCAST;
729                 dest->sin_port = htons(DHCPV4_CLIENT_PORT);
730 
731         } else if (!req->ciaddr.s_addr && reply_msg == DHCPV4_MSG_NAK) {
732                 /*
733                  * client has no previous configuration -> no IP, so we need to
734                  * reply with a broadcast packet
735                  */
736                 dest->sin_addr.s_addr = INADDR_BROADCAST;
737                 dest->sin_port = htons(DHCPV4_CLIENT_PORT);
738 
739         } else {
740                 /*
741                  * send reply to the newly allocated IP
742                  */
743                 dest->sin_addr = reply->yiaddr;
744                 dest->sin_port = htons(DHCPV4_CLIENT_PORT);
745 
746                 if (!(iface->ifflags & IFF_NOARP)) {
747                         struct arpreq arp = { .arp_flags = ATF_COM };
748 
749                         memcpy(arp.arp_ha.sa_data, req->chaddr, 6);
750                         memcpy(&arp.arp_pa, dest, sizeof(arp.arp_pa));
751                         memcpy(arp.arp_dev, iface->ifname, sizeof(arp.arp_dev));
752 
753                         if (ioctl(iface->dhcpv4_event.uloop.fd, SIOCSARP, &arp) < 0)
754                                 error("ioctl(SIOCSARP): %m");
755                 }
756         }
757 }
758 
759 enum {
760         IOV_HEADER = 0,
761         IOV_MESSAGE,
762         IOV_SERVERID,
763         IOV_CLIENTID,
764         IOV_CLIENTID_DATA,
765         IOV_NETMASK,
766         IOV_ROUTER,
767         IOV_ROUTER_ADDR,
768         IOV_DNSSERVER,
769         IOV_DNSSERVER_ADDRS,
770         IOV_HOSTNAME,
771         IOV_HOSTNAME_NAME,
772         IOV_MTU,
773         IOV_BROADCAST,
774         IOV_NTP,
775         IOV_NTP_ADDR,
776         IOV_LEASETIME,
777         IOV_RENEW,
778         IOV_REBIND,
779         IOV_AUTH,
780         IOV_AUTH_BODY,
781         IOV_SRCH_DOMAIN,
782         IOV_SRCH_DOMAIN_NAME,
783         IOV_FR_NONCE_CAP,
784         IOV_DNR,
785         IOV_DNR_BODY,
786         IOV_CAPTIVE_PORTAL,
787         IOV_IPV6_ONLY_PREF,
788         IOV_END,
789         IOV_PADDING,
790         IOV_TOTAL
791 };
792 
793 void dhcpv4_handle_msg(void *src_addr, void *data, size_t len,
794                 struct interface *iface, _o_unused void *our_dest_addr,
795                 send_reply_cb_t send_reply, void *opaque)
796 {
797         /* Request variables */
798         struct dhcpv4_message *req = data;
799         uint8_t req_msg = DHCPV4_MSG_REQUEST;
800         uint8_t *req_opts = NULL;
801         size_t req_opts_len = 0;
802         struct in_addr req_addr = { .s_addr = INADDR_ANY };
803         uint32_t req_leasetime = 0;
804         char *req_hostname = NULL;
805         size_t req_hostname_len = 0;
806         uint8_t *req_clientid = NULL;
807         size_t req_clientid_len = 0;
808         bool req_accept_fr = false;
809         bool ipv6_only = false;
810 
811         /* Reply variables */
812         struct dhcpv4_message reply = {
813                 .op = DHCPV4_OP_BOOTREPLY,
814                 .htype = ARPHRD_ETHER,
815                 .hlen = ETH_ALEN,
816                 .hops = 0,
817                 .xid = req->xid,
818                 .secs = 0,
819                 .flags = req->flags,
820                 .ciaddr = { INADDR_ANY },
821                 .yiaddr = { INADDR_ANY },
822                 .siaddr = iface->dhcpv4_own_ip.addr.in,
823                 .giaddr = req->giaddr,
824                 .chaddr = { 0 },
825                 .sname = { 0 },
826                 .file = { 0 },
827                 .cookie = htonl(DHCPV4_MAGIC_COOKIE),
828         };
829         struct dhcpv4_option_u8 reply_msg = {
830                 .code = DHCPV4_OPT_MESSAGE,
831                 .len = sizeof(uint8_t),
832                 .data = DHCPV4_MSG_ACK,
833         };
834         struct dhcpv4_option_u32 reply_serverid = {
835                 .code = DHCPV4_OPT_SERVERID,
836                 .len = sizeof(struct in_addr),
837                 .data = iface->dhcpv4_own_ip.addr.in.s_addr,
838         };
839         struct dhcpv4_option reply_clientid = {
840                 .code = DHCPV4_OPT_CLIENTID,
841         };
842         struct dhcpv4_option_u32 reply_netmask = {
843                 .code = DHCPV4_OPT_NETMASK,
844                 .len = sizeof(uint32_t),
845         };
846         struct dhcpv4_option reply_router = {
847                 .code = DHCPV4_OPT_ROUTER,
848         };
849         struct dhcpv4_option reply_dnsserver = {
850                 .code = DHCPV4_OPT_DNSSERVER,
851         };
852         struct dhcpv4_option reply_hostname = {
853                 .code = DHCPV4_OPT_HOSTNAME,
854         };
855         struct dhcpv4_option_u16 reply_mtu = {
856                 .code = DHCPV4_OPT_MTU,
857                 .len = sizeof(uint16_t),
858         };
859         struct dhcpv4_option_u32 reply_broadcast = {
860                 .code = DHCPV4_OPT_BROADCAST,
861                 .len = sizeof(uint32_t),
862         };
863         struct dhcpv4_option reply_ntp = {
864                 .code = DHCPV4_OPT_NTPSERVER,
865                 .len = iface->dhcpv4_ntp_cnt * sizeof(*iface->dhcpv4_ntp),
866         };
867         struct dhcpv4_option_u32 reply_leasetime = {
868                 .code = DHCPV4_OPT_LEASETIME,
869                 .len = sizeof(uint32_t),
870         };
871         struct dhcpv4_option_u32 reply_renew = {
872                 .code = DHCPV4_OPT_RENEW,
873                 .len = sizeof(uint32_t),
874         };
875         struct dhcpv4_option_u32 reply_rebind = {
876                 .code = DHCPV4_OPT_REBIND,
877                 .len = sizeof(uint32_t),
878         };
879         struct dhcpv4_auth_forcerenew reply_auth_body = {
880                 .protocol = DHCPV4_AUTH_PROTO_RKAP,
881                 .algorithm = DHCPV4_AUTH_ALG_HMAC_MD5,
882                 .rdm = DHCPV4_AUTH_RDM_MONOTONIC,
883                 .type = DHCPV4_AUTH_RKAP_AI_TYPE_KEY,
884                 .key = { 0 },
885         };
886         struct dhcpv4_option reply_auth = {
887                 .code = DHCPV4_OPT_AUTHENTICATION,
888                 .len = sizeof(reply_auth_body),
889         };
890         struct dhcpv4_option reply_srch_domain = {
891                 .code = DHCPV4_OPT_DNS_DOMAIN_SEARCH,
892         };
893         struct dhcpv4_option_u8 reply_fr_nonce_cap = {
894                 .code = DHCPV4_OPT_FORCERENEW_NONCE_CAPABLE,
895                 .len = sizeof(uint8_t),
896                 .data = 1,
897         };
898         struct dhcpv4_option reply_dnr = {
899                 .code = DHCPV4_OPT_DNR,
900         };
901         struct dhcpv4_option_u32 reply_ipv6_only = {
902                 .code = DHCPV4_OPT_IPV6_ONLY_PREFERRED,
903                 .len = sizeof(uint32_t),
904                 .data = htonl(iface->dhcpv4_v6only_wait),
905         };
906         uint8_t reply_end = DHCPV4_OPT_END;
907 
908         struct iovec iov[IOV_TOTAL] = {
909                 [IOV_HEADER]            = { &reply, sizeof(reply) },
910                 [IOV_MESSAGE]           = { &reply_msg, sizeof(reply_msg) },
911                 [IOV_SERVERID]          = { &reply_serverid, sizeof(reply_serverid) },
912                 [IOV_CLIENTID]          = { &reply_clientid, 0 },
913                 [IOV_CLIENTID_DATA]     = { NULL, 0 },
914                 [IOV_NETMASK]           = { &reply_netmask, 0 },
915                 [IOV_ROUTER]            = { &reply_router, 0 },
916                 [IOV_ROUTER_ADDR]       = { NULL, 0 },
917                 [IOV_DNSSERVER]         = { &reply_dnsserver, 0 },
918                 [IOV_DNSSERVER_ADDRS]   = { NULL, 0 },
919                 [IOV_HOSTNAME]          = { &reply_hostname, 0 },
920                 [IOV_HOSTNAME_NAME]     = { NULL, 0 },
921                 [IOV_MTU]               = { &reply_mtu, 0 },
922                 [IOV_BROADCAST]         = { &reply_broadcast, 0 },
923                 [IOV_NTP]               = { &reply_ntp, 0 },
924                 [IOV_NTP_ADDR]          = { iface->dhcpv4_ntp, 0 },
925                 [IOV_LEASETIME]         = { &reply_leasetime, 0 },
926                 [IOV_RENEW]             = { &reply_renew, 0 },
927                 [IOV_REBIND]            = { &reply_rebind, 0 },
928                 [IOV_AUTH]              = { &reply_auth, 0 },
929                 [IOV_AUTH_BODY]         = { &reply_auth_body, 0 },
930                 [IOV_SRCH_DOMAIN]       = { &reply_srch_domain, 0 },
931                 [IOV_SRCH_DOMAIN_NAME]  = { NULL, 0 },
932                 [IOV_FR_NONCE_CAP]      = { &reply_fr_nonce_cap, 0 },
933                 [IOV_DNR]               = { &reply_dnr, 0 },
934                 [IOV_DNR_BODY]          = { NULL, 0 },
935                 [IOV_CAPTIVE_PORTAL]    = { NULL, 0 },
936                 [IOV_IPV6_ONLY_PREF]    = { &reply_ipv6_only, 0 },
937                 [IOV_END]               = { &reply_end, sizeof(reply_end) },
938                 [IOV_PADDING]           = { NULL, 0 },
939         };
940 
941         /* Options which *might* be included in the reply unrequested */
942         uint8_t std_opts[] = {
943                 DHCPV4_OPT_NETMASK,
944                 DHCPV4_OPT_ROUTER,
945                 DHCPV4_OPT_DNSSERVER,
946                 DHCPV4_OPT_HOSTNAME,
947                 DHCPV4_OPT_MTU,
948                 DHCPV4_OPT_BROADCAST,
949                 DHCPV4_OPT_LEASETIME,
950                 DHCPV4_OPT_RENEW,
951                 DHCPV4_OPT_REBIND,
952                 DHCPV4_OPT_CLIENTID, // Must be in reply if present in req, RFC6842, §3
953                 DHCPV4_OPT_AUTHENTICATION,
954                 DHCPV4_OPT_DNS_DOMAIN_SEARCH,
955                 DHCPV4_OPT_CAPTIVE_PORTAL,
956                 DHCPV4_OPT_FORCERENEW_NONCE_CAPABLE,
957         };
958 
959         /* Misc */
960         struct sockaddr_in dest_addr;
961         bool reply_incl_fr = false;
962         struct dhcpv4_lease *lease = NULL;
963         uint32_t fr_serverid = INADDR_ANY;
964 
965         if (iface->dhcpv4 == MODE_DISABLED)
966                 return;
967 
968         debug("Got DHCPv4 request on %s", iface->name);
969 
970         struct dhcpv4_option *opt;
971         dhcpv4_for_each_option(req->options, (uint8_t *)data + len, opt) {
972                 switch (opt->code) {
973                 case DHCPV4_OPT_PAD:
974                         break;
975                 case DHCPV4_OPT_HOSTNAME:
976                         req_hostname = (char *)opt->data;
977                         req_hostname_len = opt->len;
978                         break;
979                 case DHCPV4_OPT_IPADDRESS:
980                         if (opt->len == 4)
981                                 memcpy(&req_addr, opt->data, 4);
982                         break;
983                 case DHCPV4_OPT_MESSAGE:
984                         if (opt->len == 1)
985                                 req_msg = opt->data[0];
986                         break;
987                 case DHCPV4_OPT_SERVERID:
988                         if (opt->len == 4 && memcmp(opt->data, &iface->dhcpv4_own_ip, 4))
989                                 return;
990                         break;
991                 case DHCPV4_OPT_REQOPTS:
992                         req_opts = opt->data;
993                         req_opts_len = opt->len;
994                         if (iface->dhcpv4_v6only_wait)
995                                 for (uint8_t i = 0; i < opt->len; i++)
996                                         if (opt->data[i] == DHCPV4_OPT_IPV6_ONLY_PREFERRED)
997                                                 ipv6_only = true;
998                         break;
999                 case DHCPV4_OPT_CLIENTID:
1000                         if (opt->len >= 2) {
1001                                 req_clientid = opt->data;
1002                                 req_clientid_len = opt->len;
1003                         }
1004                         break;
1005                 case DHCPV4_OPT_LEASETIME:
1006                         if (opt->len == 4) {
1007                                 memcpy(&req_leasetime, opt->data, 4);
1008                                 req_leasetime = ntohl(req_leasetime);
1009                         }
1010                         break;
1011                 case DHCPV4_OPT_FORCERENEW_NONCE_CAPABLE:
1012                         for (uint8_t i = 0; i < opt->len; i++) {
1013                                 if (opt->data[i] == 1) {
1014                                         req_accept_fr = true;
1015                                         break;
1016                                 }
1017                         }
1018                         break;
1019                 }
1020         }
1021 
1022         info("Received %s from %s on %s", dhcpv4_msg_to_string(req_msg),
1023              odhcpd_print_mac(req->chaddr, req->hlen), iface->name);
1024 
1025         switch (req_msg) {
1026         case DHCPV4_MSG_INFORM:
1027                 break;
1028         case DHCPV4_MSG_DECLINE:
1029         case DHCPV4_MSG_RELEASE:
1030                 dhcpv4_lease(iface, req_msg, req->chaddr, req_clientid,
1031                              req_clientid_len, req_addr, &req_leasetime,
1032                              req_hostname, req_hostname_len, req_accept_fr,
1033                              &reply_incl_fr, &fr_serverid);
1034                 return;
1035         case DHCPV4_MSG_DISCOVER:
1036                 if (ipv6_only)
1037                         break;
1038                 _o_fallthrough;
1039         case DHCPV4_MSG_REQUEST:
1040                 lease = dhcpv4_lease(iface, req_msg, req->chaddr, req_clientid,
1041                                      req_clientid_len, req_addr, &req_leasetime,
1042                                      req_hostname, req_hostname_len, req_accept_fr,
1043                                      &reply_incl_fr, &fr_serverid);
1044                 break;
1045         default:
1046                 return;
1047         }
1048 
1049         /* We are at the point where we know the client expects a reply */
1050         switch (req_msg) {
1051         case DHCPV4_MSG_DISCOVER:
1052                 if (!lease && !ipv6_only)
1053                         return;
1054                 reply_msg.data = DHCPV4_MSG_OFFER;
1055                 break;
1056 
1057         case DHCPV4_MSG_REQUEST:
1058                 if (!lease) {
1059                         reply_msg.data = DHCPV4_MSG_NAK;
1060                         break;
1061                 }
1062 
1063                 if ((req_addr.s_addr && req_addr.s_addr != lease->ipv4.s_addr) ||
1064                     (req->ciaddr.s_addr && req->ciaddr.s_addr != lease->ipv4.s_addr)) {
1065                         reply_msg.data = DHCPV4_MSG_NAK;
1066                         /*
1067                          * DHCP client requested an IP which we can't offer to him. Probably the
1068                          * client changed the network or the network has been changed. The reply
1069                          * type is set to DHCPV4_MSG_NAK, because the client should not use that IP.
1070                          *
1071                          * For modern devices we build an answer that includes a valid IP, like
1072                          * a DHCPV4_MSG_ACK. The client will use that IP and doesn't need to
1073                          * perform additional DHCP round trips.
1074                          *
1075                          * Buggy clients do serverid checking in nack messages; therefore set the
1076                          * serverid in nack messages triggered by a previous force renew equal to
1077                          * the server id in use at that time by the server
1078                          *
1079                          */
1080                         if (fr_serverid)
1081                                 reply_serverid.data = fr_serverid;
1082 
1083                         if (req->ciaddr.s_addr &&
1084                             ((iface->dhcpv4_start_ip.s_addr & iface->dhcpv4_own_ip.netmask) !=
1085                              (req->ciaddr.s_addr & iface->dhcpv4_own_ip.netmask)))
1086                                 req->ciaddr.s_addr = INADDR_ANY;
1087                 }
1088                 break;
1089         }
1090 
1091         /* Note: each option might get called more than once */
1092         for (size_t i = 0; i < sizeof(std_opts) + req_opts_len; i++) {
1093                 uint8_t r_opt = i < sizeof(std_opts) ? std_opts[i] : req_opts[i - sizeof(std_opts)];
1094 
1095                 switch (r_opt) {
1096                 case DHCPV4_OPT_NETMASK:
1097                         if (!lease)
1098                                 break;
1099                         reply_netmask.data = iface->dhcpv4_own_ip.netmask;
1100                         iov[IOV_NETMASK].iov_len = sizeof(reply_netmask);
1101                         break;
1102 
1103                 case DHCPV4_OPT_ROUTER:
1104                         iov[IOV_ROUTER].iov_len = sizeof(reply_router);
1105                         if (iface->dhcpv4_routers_cnt) {
1106                                 reply_router.len = iface->dhcpv4_routers_cnt * sizeof(*iface->dhcpv4_routers);
1107                                 iov[IOV_ROUTER_ADDR].iov_base = iface->dhcpv4_routers;
1108                         } else {
1109                                 reply_router.len = sizeof(iface->dhcpv4_own_ip.addr.in);
1110                                 iov[IOV_ROUTER_ADDR].iov_base = &iface->dhcpv4_own_ip.addr.in;
1111                         }
1112                         iov[IOV_ROUTER_ADDR].iov_len = reply_router.len;
1113                         break;
1114 
1115                 case DHCPV4_OPT_DNSSERVER:
1116                         iov[IOV_DNSSERVER].iov_len = sizeof(reply_dnsserver);
1117                         if (iface->dns_addrs4_cnt) {
1118                                 reply_dnsserver.len = iface->dns_addrs4_cnt * sizeof(*iface->dns_addrs4);
1119                                 iov[IOV_DNSSERVER_ADDRS].iov_base = iface->dns_addrs4;
1120                         } else {
1121                                 reply_dnsserver.len = sizeof(iface->dhcpv4_own_ip.addr.in);
1122                                 iov[IOV_DNSSERVER_ADDRS].iov_base = &iface->dhcpv4_own_ip.addr.in;
1123                         }
1124                         iov[IOV_DNSSERVER_ADDRS].iov_len = reply_dnsserver.len;
1125                         break;
1126 
1127                 case DHCPV4_OPT_HOSTNAME:
1128                         if (!lease || !lease->hostname)
1129                                 break;
1130                         reply_hostname.len = strlen(lease->hostname);
1131                         iov[IOV_HOSTNAME].iov_len = sizeof(reply_hostname);
1132                         iov[IOV_HOSTNAME_NAME].iov_base = lease->hostname;
1133                         iov[IOV_HOSTNAME_NAME].iov_len = reply_hostname.len;
1134                         break;
1135 
1136                 case DHCPV4_OPT_MTU:
1137                         if (iov[IOV_MTU].iov_len)
1138                                 break;
1139 
1140                         struct ifreq ifr = { .ifr_name = { 0x0, } };
1141 
1142                         strncpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name) - 1);
1143                         if (!ioctl(iface->dhcpv4_event.uloop.fd, SIOCGIFMTU, &ifr)) {
1144                                 reply_mtu.data = htons(ifr.ifr_mtu);
1145                                 iov[IOV_MTU].iov_len = sizeof(reply_mtu);
1146                         }
1147                         break;
1148 
1149                 case DHCPV4_OPT_BROADCAST:
1150                         if (!lease || iface->dhcpv4_own_ip.broadcast.s_addr == INADDR_ANY)
1151                                 break;
1152                         reply_broadcast.data = iface->dhcpv4_own_ip.broadcast.s_addr;
1153                         iov[IOV_BROADCAST].iov_len = sizeof(reply_broadcast);
1154                         break;
1155 
1156                 case DHCPV4_OPT_NTPSERVER:
1157                         if (!lease)
1158                                 break;
1159                         iov[IOV_NTP].iov_len = sizeof(reply_ntp);
1160                         iov[IOV_NTP_ADDR].iov_len = iface->dhcpv4_ntp_cnt * sizeof(*iface->dhcpv4_ntp);
1161                         break;
1162 
1163                 case DHCPV4_OPT_LEASETIME:
1164                         if (!lease)
1165                                 break;
1166                         reply_leasetime.data = htonl(req_leasetime);
1167                         iov[IOV_LEASETIME].iov_len = sizeof(reply_leasetime);
1168                         break;
1169 
1170                 case DHCPV4_OPT_RENEW:
1171                         if (!lease || req_leasetime == UINT32_MAX)
1172                                 break;
1173                         reply_renew.data = htonl(500 * req_leasetime / 1000);
1174                         iov[IOV_RENEW].iov_len = sizeof(reply_renew);
1175                         break;
1176 
1177                 case DHCPV4_OPT_REBIND:
1178                         if (!lease || req_leasetime == UINT32_MAX)
1179                                 break;
1180                         reply_rebind.data = htonl(875 * req_leasetime / 1000);
1181                         iov[IOV_REBIND].iov_len = sizeof(reply_rebind);
1182                         break;
1183 
1184                 case DHCPV4_OPT_CLIENTID:
1185                         if (!req_clientid)
1186                                 break;
1187                         reply_clientid.len = req_clientid_len;
1188                         iov[IOV_CLIENTID].iov_len = sizeof(reply_clientid);
1189                         iov[IOV_CLIENTID_DATA].iov_base = req_clientid;
1190                         iov[IOV_CLIENTID_DATA].iov_len = req_clientid_len;
1191                         break;
1192 
1193                 case DHCPV4_OPT_AUTHENTICATION:
1194                         if (!lease || !reply_incl_fr || req_msg != DHCPV4_MSG_REQUEST)
1195                                 break;
1196 
1197                         memcpy(reply_auth_body.key, lease->key, sizeof(reply_auth_body.key));
1198                         reply_auth_body.replay[0] = htonl(time(NULL));
1199                         reply_auth_body.replay[1] = htonl(++serial);
1200                         iov[IOV_AUTH].iov_len = sizeof(reply_auth);
1201                         iov[IOV_AUTH_BODY].iov_len = sizeof(reply_auth_body);
1202                         break;
1203 
1204                 case DHCPV4_OPT_DNS_DOMAIN_SEARCH:
1205                         if (iov[IOV_SRCH_DOMAIN].iov_len || iface->dns_search_len > UINT8_MAX)
1206                                 break;
1207 
1208                         if (iface->dns_search) {
1209                                 reply_srch_domain.len = iface->dns_search_len;
1210                                 iov[IOV_SRCH_DOMAIN].iov_len = sizeof(reply_srch_domain);
1211                                 iov[IOV_SRCH_DOMAIN_NAME].iov_base = iface->dns_search;
1212                                 iov[IOV_SRCH_DOMAIN_NAME].iov_len = iface->dns_search_len;
1213                         }
1214                         break;
1215 
1216                 case DHCPV4_OPT_FORCERENEW_NONCE_CAPABLE:
1217                         if (!lease || !reply_incl_fr || req_msg == DHCPV4_MSG_REQUEST)
1218                                 break;
1219 
1220                         iov[IOV_FR_NONCE_CAP].iov_len = sizeof(reply_fr_nonce_cap);
1221                         break;
1222 
1223                 case DHCPV4_OPT_DNR:
1224                         struct dhcpv4_dnr *dnrs;
1225                         size_t dnrs_len = 0;
1226 
1227                         if (!lease || reply_dnr.len > 0)
1228                                 break;
1229 
1230                         for (size_t j = 0; j < iface->dnr_cnt; j++) {
1231                                 struct dnr_options *dnr = &iface->dnr[j];
1232 
1233                                 if (dnr->addr4_cnt == 0 && dnr->addr6_cnt > 0)
1234                                         continue;
1235 
1236                                 dnrs_len += sizeof(struct dhcpv4_dnr);
1237                                 dnrs_len += dnr->adn_len;
1238 
1239                                 if (dnr->addr4_cnt > 0 || dnr->svc_len > 0) {
1240                                         dnrs_len += sizeof(uint8_t);
1241                                         dnrs_len += dnr->addr4_cnt * sizeof(*dnr->addr4);
1242                                         dnrs_len += dnr->svc_len;
1243                                 }
1244                         }
1245 
1246                         if (dnrs_len > UINT8_MAX)
1247                                 break;
1248 
1249                         dnrs = alloca(dnrs_len);
1250                         uint8_t *pos = (uint8_t *)dnrs;
1251 
1252                         for (size_t j = 0; j < iface->dnr_cnt; j++) {
1253                                 struct dnr_options *dnr = &iface->dnr[j];
1254                                 struct dhcpv4_dnr *d4dnr = (struct dhcpv4_dnr *)pos;
1255                                 uint16_t d4dnr_len = sizeof(uint16_t) + sizeof(uint8_t) + dnr->adn_len;
1256                                 uint16_t d4dnr_priority_be = htons(dnr->priority);
1257                                 uint16_t d4dnr_len_be;
1258 
1259                                 if (dnr->addr4_cnt == 0 && dnr->addr6_cnt > 0)
1260                                         continue;
1261 
1262                                 /* memcpy as the struct is unaligned */
1263                                 memcpy(&d4dnr->priority, &d4dnr_priority_be, sizeof(d4dnr_priority_be));
1264 
1265                                 d4dnr->adn_len = dnr->adn_len;
1266                                 pos = d4dnr->body;
1267                                 memcpy(pos, dnr->adn, dnr->adn_len);
1268                                 pos += dnr->adn_len;
1269 
1270                                 if (dnr->addr4_cnt > 0 || dnr->svc_len > 0) {
1271                                         uint8_t addr4_len = dnr->addr4_cnt * sizeof(*dnr->addr4);
1272 
1273                                         *(pos++) = addr4_len;
1274                                         memcpy(pos, dnr->addr4, addr4_len);
1275                                         pos += addr4_len;
1276                                         memcpy(pos, dnr->svc, dnr->svc_len);
1277                                         pos += dnr->svc_len;
1278 
1279                                         d4dnr_len += sizeof(addr4_len) + addr4_len + dnr->svc_len;
1280                                 }
1281 
1282                                 d4dnr_len_be = htons(d4dnr_len);
1283                                 memcpy(&d4dnr->len, &d4dnr_len_be, sizeof(d4dnr_len_be));
1284                         }
1285 
1286                         reply_dnr.len = dnrs_len;
1287                         iov[IOV_DNR].iov_len = sizeof(reply_dnr);
1288                         iov[IOV_DNR_BODY].iov_base = dnrs;
1289                         iov[IOV_DNR_BODY].iov_len = dnrs_len;
1290                         break;
1291 
1292                 case DHCPV4_OPT_IPV6_ONLY_PREFERRED:
1293                         if (iface->dhcpv4_v6only_wait)
1294                                 iov[IOV_IPV6_ONLY_PREF].iov_len = sizeof(reply_ipv6_only);
1295                         break;
1296 
1297                 case DHCPV4_OPT_CAPTIVE_PORTAL:
1298                         size_t uri_len = iface->captive_portal_uri_len;
1299                         if (uri_len == 0 || uri_len > UINT8_MAX)
1300                                 break;
1301 
1302                         uint8_t *buf = alloca(2 + uri_len);
1303                         struct dhcpv4_option *cp_opt = (struct dhcpv4_option *)buf;
1304 
1305                         cp_opt->code = DHCPV4_OPT_CAPTIVE_PORTAL;
1306                         cp_opt->len  = uri_len;
1307                         memcpy(cp_opt->data, iface->captive_portal_uri, uri_len);
1308 
1309                         iov[IOV_CAPTIVE_PORTAL].iov_base = cp_opt;
1310                         iov[IOV_CAPTIVE_PORTAL].iov_len  = 2 + uri_len;
1311                         break;
1312                 }
1313         }
1314 
1315         if (lease)
1316                 reply.yiaddr = lease->ipv4;
1317 
1318         memcpy(reply.chaddr, req->chaddr, sizeof(reply.chaddr));
1319         dhcpv4_set_dest_addr(iface, reply_msg.data, req, &reply, src_addr, &dest_addr);
1320         dhcpv4_add_padding(iov, ARRAY_SIZE(iov));
1321 
1322         if (send_reply(iov, ARRAY_SIZE(iov), (struct sockaddr *)&dest_addr, sizeof(dest_addr), opaque) < 0) {
1323                 char ipv4_str[INET_ADDRSTRLEN];
1324 
1325                 error("Failed to send %s to %s - %s: %m",
1326                       dhcpv4_msg_to_string(reply_msg.data),
1327                       dest_addr.sin_addr.s_addr == INADDR_BROADCAST ?
1328                       "ff:ff:ff:ff:ff:ff": odhcpd_print_mac(req->chaddr, req->hlen),
1329                       inet_ntop(AF_INET, &dest_addr.sin_addr, ipv4_str, sizeof(ipv4_str)));
1330         } else {
1331                 char ipv4_str[INET_ADDRSTRLEN];
1332 
1333                 error("Sent %s to %s - %s",
1334                       dhcpv4_msg_to_string(reply_msg.data),
1335                       dest_addr.sin_addr.s_addr == INADDR_BROADCAST ?
1336                       "ff:ff:ff:ff:ff:ff": odhcpd_print_mac(req->chaddr, req->hlen),
1337                       inet_ntop(AF_INET, &dest_addr.sin_addr, ipv4_str, sizeof(ipv4_str)));
1338         }
1339 
1340         if (reply_msg.data == DHCPV4_MSG_ACK && lease)
1341                 ubus_bcast_dhcpv4_event("dhcp.lease4", iface->ifname, lease);
1342 }
1343 
1344 /* Handler for DHCPv4 messages */
1345 static void dhcpv4_handle_dgram(void *addr, void *data, size_t len,
1346                                 struct interface *iface, _o_unused void *dest_addr)
1347 {
1348         int sock = iface->dhcpv4_event.uloop.fd;
1349 
1350         dhcpv4_handle_msg(addr, data, len, iface, dest_addr, dhcpv4_send_reply, &sock);
1351 }
1352 
1353 static bool dhcpv4_setup_addresses(struct interface *iface)
1354 {
1355         uint32_t pool_start = iface->dhcpv4_pool_start;
1356         uint32_t pool_end = iface->dhcpv4_pool_end;
1357 
1358         iface->dhcpv4_start_ip.s_addr = INADDR_ANY;
1359         iface->dhcpv4_end_ip.s_addr = INADDR_ANY;
1360         iface->dhcpv4_own_ip = (struct odhcpd_ipaddr){ .addr.in.s_addr = INADDR_ANY };
1361 
1362         if (iface->no_dynamic_dhcp) {
1363                 if (!iface->oaddrs4_cnt)
1364                         goto error;
1365 
1366                 iface->dhcpv4_own_ip = iface->oaddrs4[0];
1367                 info("DHCPv4: providing static leases on interface '%s'", iface->name);
1368                 return true;
1369         }
1370 
1371         for (size_t i = 0; i < iface->oaddrs4_cnt; i++) {
1372                 struct odhcpd_ipaddr *oaddr = &iface->oaddrs4[i];
1373                 uint32_t hostmask = ntohl(~oaddr->netmask);
1374                 char pool_start_str[INET_ADDRSTRLEN];
1375                 char pool_end_str[INET_ADDRSTRLEN];
1376 
1377                 if (oaddr->prefix_len > DHCPV4_MAX_PREFIX_LEN)
1378                         continue;
1379 
1380                 if (addr_is_fr_ip(iface, &oaddr->addr.in))
1381                         continue;
1382 
1383                 /* pool_start outside range? */
1384                 if (pool_start && ((pool_start & hostmask) != pool_start))
1385                         continue;
1386 
1387                 /* pool_end outside range? */
1388                 if (pool_end && ((pool_end & hostmask) != pool_end))
1389                         continue;
1390 
1391                 /* pool_end == broadcast? */
1392                 if (pool_end && (pool_end == hostmask))
1393                         continue;
1394 
1395                 if (!pool_start || !pool_end) {
1396                         switch (oaddr->prefix_len) {
1397                         case 28:
1398                                 pool_start = 3;
1399                                 pool_end = 12;
1400                                 break;
1401                         case 27:
1402                                 pool_start = 10;
1403                                 pool_end = 29;
1404                                 break;
1405                         case 26:
1406                                 pool_start = 10;
1407                                 pool_end = 59;
1408                                 break;
1409                         case 25:
1410                                 pool_start = 20;
1411                                 pool_end = 119;
1412                                 break;
1413                         default: /* <= 24 */
1414                                 pool_start = 100;
1415                                 pool_end = 249;
1416                                 break;
1417                         }
1418                 }
1419 
1420                 iface->dhcpv4_start_ip.s_addr = (oaddr->addr.in.s_addr & oaddr->netmask) | htonl(pool_start);
1421                 iface->dhcpv4_end_ip.s_addr = (oaddr->addr.in.s_addr & oaddr->netmask) | htonl(pool_end);
1422                 iface->dhcpv4_own_ip = *oaddr;
1423 
1424                 info("DHCPv4: providing dynamic/static leases on interface '%s', pool: %s - %s", iface->name,
1425                      inet_ntop(AF_INET, &iface->dhcpv4_start_ip, pool_start_str, sizeof(pool_start_str)),
1426                      inet_ntop(AF_INET, &iface->dhcpv4_end_ip, pool_end_str, sizeof(pool_end_str)));
1427                 return true;
1428         }
1429 
1430 error:
1431         warn("DHCPv4: no suitable networks on interface '%s'", iface->name);
1432         return false;
1433 }
1434 
1435 struct dhcpv4_packet {
1436         struct udphdr udp;
1437         struct dhcpv4_message dhcp;
1438 } _o_packed;
1439 
1440 bool dhcpv4_setup_interface(struct interface *iface, bool enable)
1441 {
1442         /* Note: we could check more things (but buggy clients exist), e.g.:
1443          *  - DHCPV4_MIN_PACKET_SIZE
1444          *  - yiaddr zero
1445          *  - siaddr zero
1446          */
1447         static const struct sock_filter filter[] = {
1448                 BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0),                                          /* A <- packet length */
1449                 BPF_JUMP(BPF_JMP + BPF_JGT + BPF_K,
1450                          offsetof(struct dhcpv4_packet, dhcp.options), 1, 0),                   /* A > offsetof(dhcp.options)? */
1451                 BPF_STMT(BPF_RET + BPF_K, 0),                                                   /* false -> drop */
1452 
1453                 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct dhcpv4_packet, dhcp.op)),    /* A <- dhcp.op */
1454                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCPV4_OP_BOOTREQUEST, 1, 0),               /* A == DHCPV4_OP_BOOTREQUEST? */
1455                 BPF_STMT(BPF_RET + BPF_K, 0),                                                   /* false -> drop */
1456 
1457                 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct dhcpv4_packet, dhcp.htype)), /* A <- dhcp.htype */
1458                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0),                        /* A == ARPHRD_ETHER? */
1459                 BPF_STMT(BPF_RET + BPF_K, 0),                                                   /* false -> drop */
1460 
1461                 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct dhcpv4_packet, dhcp.hlen)),  /* A <- dhcp.hlen */
1462                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 1, 0),                            /* A == ETH_ALEN? */
1463                 BPF_STMT(BPF_RET + BPF_K, 0),                                                   /* false -> drop */
1464 
1465                 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct dhcpv4_packet, dhcp.cookie)),/* A <- dhcp.cookie */
1466                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCPV4_MAGIC_COOKIE, 1, 0),                 /* A == DHCPV4_MAGIC_COOKIE? */
1467                 BPF_STMT(BPF_RET + BPF_K, 0),                                                   /* false -> drop */
1468 
1469                 BPF_STMT(BPF_RET + BPF_K, UINT32_MAX),                                          /* accept */
1470         };
1471         static const struct sock_fprog bpf = {
1472                 .len = ARRAY_SIZE(filter),
1473                 .filter = (struct sock_filter *)filter,
1474         };
1475         const struct sockaddr_in bind_addr = {
1476                 .sin_family = AF_INET,
1477                 .sin_port = htons(DHCPV4_SERVER_PORT),
1478                 .sin_addr = { INADDR_ANY },
1479         };
1480         int val;
1481         int fd;
1482 
1483         if (iface->dhcpv4_event.uloop.fd >= 0) {
1484                 uloop_fd_delete(&iface->dhcpv4_event.uloop);
1485                 close(iface->dhcpv4_event.uloop.fd);
1486                 iface->dhcpv4_event.uloop.fd = -1;
1487         }
1488 
1489         if (!enable || iface->dhcpv4 == MODE_DISABLED) {
1490                 struct dhcpv4_lease *lease, *tmp;
1491 
1492                 avl_remove_all_elements(&iface->dhcpv4_leases, lease, iface_avl, tmp)
1493                         dhcpv4_free_lease(lease);
1494                 return true;
1495         }
1496 
1497         fd = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
1498         if (fd < 0) {
1499                 error("socket(AF_INET): %m");
1500                 goto error;
1501         }
1502 
1503         if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)) < 0) {
1504                 error("setsockopt(SO_ATTACH_FILTER): %m");
1505                 goto error;
1506         }
1507 
1508         val = 1;
1509         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
1510                 error("setsockopt(SO_REUSEADDR): %m");
1511                 goto error;
1512         }
1513 
1514         if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)) < 0) {
1515                 error("setsockopt(SO_BROADCAST): %m");
1516                 goto error;
1517         }
1518 
1519         if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val)) < 0) {
1520                 error("setsockopt(IP_PKTINFO): %m");
1521                 goto error;
1522         }
1523 
1524         val = IPTOS_CLASS_CS6;
1525         if (setsockopt(fd, IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0) {
1526                 error("setsockopt(IP_TOS): %m");
1527                 goto error;
1528         }
1529 
1530         val = IP_PMTUDISC_DONT;
1531         if (setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val)) < 0) {
1532                 error("setsockopt(IP_MTU_DISCOVER): %m");
1533                 goto error;
1534         }
1535 
1536         if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, iface->ifname,
1537                        strlen(iface->ifname)) < 0) {
1538                 error("setsockopt(SO_BINDTODEVICE): %m");
1539                 goto error;
1540         }
1541 
1542         if (bind(fd, (const struct sockaddr *)&bind_addr, sizeof(bind_addr)) < 0) {
1543                 error("bind(): %m");
1544                 goto error;
1545         }
1546 
1547         if (!dhcpv4_setup_addresses(iface))
1548                 goto error;
1549 
1550         iface->dhcpv4_event.uloop.fd = fd;
1551         iface->dhcpv4_event.handle_dgram = dhcpv4_handle_dgram;
1552         odhcpd_register(&iface->dhcpv4_event);
1553         return true;
1554 
1555 error:
1556         close(fd);
1557         return false;
1558 }
1559 
1560 static void dhcpv4_addrlist_change(struct interface *iface)
1561 {
1562         struct odhcpd_ipaddr ip = iface->dhcpv4_own_ip;
1563         struct odhcpd_ref_ip *a;
1564         struct dhcpv4_lease *lease;
1565 
1566         dhcpv4_setup_addresses(iface);
1567 
1568         if ((ip.addr.in.s_addr & ip.netmask) ==
1569             (iface->dhcpv4_own_ip.addr.in.s_addr & iface->dhcpv4_own_ip.netmask))
1570                 return;
1571 
1572         if (ip.addr.in.s_addr && !leases_require_fr(iface, &ip))
1573                 return;
1574 
1575         if (iface->dhcpv4_own_ip.addr.in.s_addr == INADDR_ANY)
1576                 return;
1577 
1578         if (list_empty(&iface->dhcpv4_fr_ips))
1579                 return;
1580 
1581         a = list_first_entry(&iface->dhcpv4_fr_ips, struct odhcpd_ref_ip, head);
1582 
1583         if (netlink_setup_addr(&a->addr, iface->ifindex, false, true)) {
1584                 warn("Failed to add ip address on %s", iface->name);
1585                 return;
1586         }
1587 
1588         avl_for_each_element(&iface->dhcpv4_leases, lease, iface_avl) {
1589                 if (lease->bound && lease->fr_ip && !lease->fr_cnt) {
1590                         if (lease->accept_fr_nonce || iface->dhcpv4_forcereconf)
1591                                 dhcpv4_fr_rand_delay(lease);
1592                         else
1593                                 dhcpv4_fr_stop(lease);
1594                 }
1595         }
1596 }
1597 
1598 static void dhcpv4_netevent_cb(unsigned long event, struct netevent_handler_info *info)
1599 {
1600         struct interface *iface = info->iface;
1601 
1602         if (!iface || iface->dhcpv4 == MODE_DISABLED)
1603                 return;
1604 
1605         switch (event) {
1606         case NETEV_IFINDEX_CHANGE:
1607                 dhcpv4_setup_interface(iface, true);
1608                 break;
1609         case NETEV_ADDRLIST_CHANGE:
1610                 dhcpv4_addrlist_change(iface);
1611                 break;
1612         default:
1613                 break;
1614         }
1615 }
1616 
1617 static void dhcpv4_valid_until_cb(struct uloop_timeout *event)
1618 {
1619         struct interface *iface;
1620         time_t now = odhcpd_time();
1621         bool update_statefile = false;
1622 
1623         avl_for_each_element(&interfaces, iface, avl) {
1624                 struct dhcpv4_lease *lease, *tmp;
1625 
1626                 if (iface->dhcpv4 != MODE_SERVER)
1627                         continue;
1628 
1629                 avl_for_each_element_safe(&iface->dhcpv4_leases, lease, iface_avl, tmp) {
1630                         if (!INFINITE_VALID(lease->valid_until) && lease->valid_until < now) {
1631                                 ubus_bcast_dhcpv4_event("dhcp.expire4", iface->ifname, lease);
1632                                 dhcpv4_free_lease(lease);
1633                                 update_statefile = true;
1634                         }
1635                 }
1636 
1637                 if (iface->update_statefile) {
1638                         update_statefile = true;
1639                         iface->update_statefile = false;
1640                 }
1641         }
1642 
1643         if (update_statefile)
1644                 statefiles_write();
1645 
1646         uloop_timeout_set(event, 5000);
1647 }
1648 
1649 /* Create socket and register events */
1650 int dhcpv4_init(void)
1651 {
1652         static struct netevent_handler dhcpv4_netevent_handler = { .cb = dhcpv4_netevent_cb };
1653         static struct uloop_timeout valid_until_timeout = { .cb = dhcpv4_valid_until_cb };
1654 
1655         uloop_timeout_set(&valid_until_timeout, 1000);
1656         netlink_add_netevent_handler(&dhcpv4_netevent_handler);
1657 
1658         return 0;
1659 }
1660 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt