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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt