- syslog(LOG_WARNING, "DHCPv4 dhcp addr %s", inet_ntoa(iface->dhcpv4_addr));
- syslog(LOG_WARNING, "DHCPv4 dhcp mask %s", inet_ntoa(iface->dhcpv4_mask));
- syslog(LOG_WARNING, "DHCPv4 dhcp start %s", inet_ntoa(iface->dhcpv4_start));
- syslog(LOG_WARNING, "DHCPv4 dhcp end %s", inet_ntoa(iface->dhcpv4_end));
-
-
- // Parse static entries
- struct lease *lease;
- list_for_each_entry(lease, &leases, head) {
- // Construct entry
- size_t hostlen = strlen(lease->hostname) + 1;
- struct dhcpv4_assignment *a = calloc(1, sizeof(*a) + hostlen);
- if (!a) {
- syslog(LOG_ERR, "Calloc failed for static lease on interface %s",
- iface->ifname);
- return -1;
- }
- a->addr = ntohl(lease->ipaddr.s_addr);
- memcpy(a->hwaddr, lease->mac.ether_addr_octet, sizeof(a->hwaddr));
- memcpy(a->hostname, lease->hostname, hostlen);
- a->valid_until = LONG_MAX;
-
- // Assign to all interfaces
- struct dhcpv4_assignment *c;
- list_for_each_entry(c, &iface->dhcpv4_assignments, head) {
- if (c->addr > a->addr) {
- list_add_tail(&a->head, &c->head);
- break;
- } else if (c->addr == a->addr) {
- // Already an assignment with that number
+ }
+
+ /* Don't allocate IP range for subnets bigger than 28 */
+ if (iface->addr4[0].prefix > 28) {
+ syslog(LOG_WARNING, "Auto allocation of DHCP range fails on %s", iface->name);
+ return -1;
+ }
+
+ iface->dhcpv4_local = iface->addr4[0].addr.in;
+ iface->dhcpv4_bcast = iface->addr4[0].broadcast;
+ odhcpd_bitlen2netmask(false, iface->addr4[0].prefix, &iface->dhcpv4_mask);
+ end = start = iface->dhcpv4_local.s_addr & iface->dhcpv4_mask.s_addr;
+
+ /* Auto allocate ranges */
+ if (ntohl(iface->dhcpv4_mask.s_addr) <= 0xffffff00) { /* /24, 150 of 256, [100..249] */
+ iface->dhcpv4_start_ip.s_addr = start | htonl(100);
+ iface->dhcpv4_end_ip.s_addr = end | htonl(100 + 150 - 1);
+ } else if (ntohl(iface->dhcpv4_mask.s_addr) <= 0xffffff80) { /* /25, 100 of 128, [20..119] */
+ iface->dhcpv4_start_ip.s_addr = start | htonl(20);
+ iface->dhcpv4_end_ip.s_addr = end | htonl(20 + 100 - 1);
+ } else if (ntohl(iface->dhcpv4_mask.s_addr) <= 0xffffffc0) { /* /26, 50 of 64, [10..59] */
+ iface->dhcpv4_start_ip.s_addr = start | htonl(10);
+ iface->dhcpv4_end_ip.s_addr = end | htonl(10 + 50 - 1);
+ } else if (ntohl(iface->dhcpv4_mask.s_addr) <= 0xffffffe0) { /* /27, 20 of 32, [10..29] */
+ iface->dhcpv4_start_ip.s_addr = start | htonl(10);
+ iface->dhcpv4_end_ip.s_addr = end | htonl(10 + 20 - 1);
+ } else { /* /28, 10 of 16, [3..12] */
+ iface->dhcpv4_start_ip.s_addr = start | htonl(3);
+ iface->dhcpv4_end_ip.s_addr = end | htonl(3 + 10 - 1);
+ }
+
+ return 0;
+}
+
+static void inc_ref_cnt_ip(struct odhcpd_ref_ip **ptr, struct odhcpd_ref_ip *ip)
+{
+ *ptr = ip;
+ ip->ref_cnt++;
+}
+
+static void decr_ref_cnt_ip(struct odhcpd_ref_ip **ptr, struct interface *iface)
+{
+ struct odhcpd_ref_ip *ip = *ptr;
+
+ if (--ip->ref_cnt == 0) {
+ netlink_setup_addr(&ip->addr, iface->ifindex, false, false);
+
+ list_del(&ip->head);
+ free(ip);
+ }
+
+ *ptr = NULL;
+}
+
+static bool addr_is_fr_ip(struct interface *iface, struct in_addr *addr)
+{
+ struct odhcpd_ref_ip *p;
+
+ list_for_each_entry(p, &iface->dhcpv4_fr_ips, head) {
+ if (addr->s_addr == p->addr.addr.in.s_addr)
+ return true;
+ }
+
+ return false;
+}
+
+static bool leases_require_fr(struct interface *iface, struct odhcpd_ipaddr *addr,
+ uint32_t mask)
+{
+ struct dhcp_assignment *a = NULL;
+ struct odhcpd_ref_ip *fr_ip = NULL;
+
+ list_for_each_entry(a, &iface->dhcpv4_assignments, head) {
+ if ((a->accept_fr_nonce || iface->dhcpv4_forcereconf) &&
+ !a->fr_ip &&
+ ((a->addr & mask) == (addr->addr.in.s_addr & mask))) {
+ if (!fr_ip) {
+ fr_ip = calloc(1, sizeof(*fr_ip));
+ if (!fr_ip)