/* ARGSUSED */ void dhcp_renew(iu_tq_t *tqp, void *arg) { dhcp_lease_t *dlp = arg; dhcp_smach_t *dsmp = dlp->dl_smach; uint32_t t2; dhcpmsg(MSG_VERBOSE, "dhcp_renew: T1 timer expired on %s", dsmp->dsm_name); dlp->dl_t1.dt_id = -1; if (dsmp->dsm_state == RENEWING || dsmp->dsm_state == REBINDING) { dhcpmsg(MSG_DEBUG, "dhcp_renew: already renewing"); release_lease(dlp); return; } /* * Sanity check: don't send packets if we're past T2, or if we're * extremely close. */ t2 = dsmp->dsm_curstart_monosec + dlp->dl_t2.dt_start; if (monosec() + TOO_CLOSE >= t2) { dhcpmsg(MSG_DEBUG, "dhcp_renew: %spast T2 on %s", monosec() > t2 ? "" : "almost ", dsmp->dsm_name); release_lease(dlp); return; } /* * If there isn't an async event pending, or if we can cancel the one * that's there, then try to renew by sending an extension request. If * that fails, we'll try again when the next timer fires. */ if (!async_cancel(dsmp) || !async_start(dsmp, DHCP_EXTEND, B_FALSE) || !dhcp_extending(dsmp)) { if (monosec() + RETRY_DELAY < t2) { /* * Try again in RETRY_DELAY seconds; user command * should be gone. */ init_timer(&dlp->dl_t1, RETRY_DELAY); (void) set_smach_state(dsmp, BOUND); if (!schedule_lease_timer(dlp, &dlp->dl_t1, dhcp_renew)) { dhcpmsg(MSG_INFO, "dhcp_renew: unable to " "reschedule renewal around user command " "on %s; will wait for rebind", dsmp->dsm_name); } } else { dhcpmsg(MSG_DEBUG, "dhcp_renew: user busy on %s; will " "wait for rebind", dsmp->dsm_name); } } release_lease(dlp); }
void periodic_scan(void *p) { time_t x, y; struct subnet *n; struct group *g; struct shared_network *s; struct lease *l; /* find the shortest lease this server gives out */ x = MIN(root_group.default_lease_time, root_group.max_lease_time); for (n = subnets; n; n = n->next_subnet) for (g = n->group; g; g = g->next) x = MIN(x, g->default_lease_time); /* use half of the shortest lease as the scan interval */ y = x / 2; if (y < 1) y = 1; /* walk across all leases to find the exired ones */ for (n = subnets; n; n = n->next_subnet) for (g = n->group; g; g = g->next) for (s = g->shared_network; s; s = s->next) for (l = s->leases; l && l->ends; l = l->next) if (cur_time >= l->ends){ release_lease(l); pfmsg('R', l); } add_timeout(cur_time + y, periodic_scan, NULL); }
void lease_ping_timeout(void *vlp) { struct lease *lp = vlp; --outstanding_pings; if (lp->releasing) { lp->releasing = 0; release_lease(lp); } else dhcp_reply(lp); }
int find_lease( DHCPLEASE *dhcpl, u32b xid, u8b chaddr[] ) { int result = -2; DHCPLIST *temp; if( !dhcpl ) return -1; for( temp = list; temp; temp=temp->next ) if( !maccmp( temp->chaddr, chaddr ) ) release_lease( dhcpl, xid, chaddr); for( temp = list; temp; temp=temp->next ) if( ( !maccmp( temp->chaddr, chaddr )) && ( temp->type == STATIC )) { dhcpl->ip = temp->data.ip; dhcpl->router = temp->data.router; dhcpl->mask = temp->data.mask; dhcpl->lease = temp->data.lease; dhcpl->siaddr = temp->data.siaddr; fprintf( stdout, "Assigning Static IP! \n"); temp->available = PROCESSING; temp->xid = xid; temp->ltime = MAX_PROCESS_TIME; maccpy( temp->chaddr, chaddr); result = 0; return result; } else if( ( temp->available & FREE ) && ( temp->type == DYNAMIC )) { dhcpl->ip = temp->data.ip; dhcpl->router = temp->data.router; dhcpl->mask = temp->data.mask; dhcpl->lease = temp->data.lease; dhcpl->siaddr = temp->data.siaddr; fprintf( stdout, "Assigning Dynamic IP! \n"); temp->available = PROCESSING; temp->xid = xid; temp->ltime = MAX_PROCESS_TIME; maccpy( temp->chaddr, chaddr); result = 0; return result; } return result; }
/* ARGSUSED */ void dhcp_rebind(iu_tq_t *tqp, void *arg) { dhcp_lease_t *dlp = arg; dhcp_smach_t *dsmp = dlp->dl_smach; int nlifs; dhcp_lif_t *lif; boolean_t some_valid; uint32_t expiremax; DHCPSTATE oldstate; dhcpmsg(MSG_VERBOSE, "dhcp_rebind: T2 timer expired on %s", dsmp->dsm_name); dlp->dl_t2.dt_id = -1; if ((oldstate = dsmp->dsm_state) == REBINDING) { dhcpmsg(MSG_DEBUG, "dhcp_renew: already rebinding"); release_lease(dlp); return; } /* * Sanity check: don't send packets if we've already expired on all of * the addresses. We compute the maximum expiration time here, because * it won't matter for v4 (there's only one lease) and for v6 we need * to know when the last lease ages away. */ some_valid = B_FALSE; expiremax = monosec(); lif = dlp->dl_lifs; for (nlifs = dlp->dl_nlifs; nlifs > 0; nlifs--, lif = lif->lif_next) { uint32_t expire; expire = dsmp->dsm_curstart_monosec + lif->lif_expire.dt_start; if (expire > expiremax) { expiremax = expire; some_valid = B_TRUE; } } if (!some_valid) { dhcpmsg(MSG_DEBUG, "dhcp_rebind: all leases expired on %s", dsmp->dsm_name); release_lease(dlp); return; } /* * This is our first venture into the REBINDING state, so reset the * server address. We know the renew timer has already been cancelled * (or we wouldn't be here). */ if (dsmp->dsm_isv6) { dsmp->dsm_server = ipv6_all_dhcp_relay_and_servers; } else { IN6_IPADDR_TO_V4MAPPED(htonl(INADDR_BROADCAST), &dsmp->dsm_server); } /* {Bound,Renew}->rebind transitions cannot fail */ (void) set_smach_state(dsmp, REBINDING); /* * If there isn't an async event pending, or if we can cancel the one * that's there, then try to rebind by sending an extension request. * If that fails, we'll clean up when the lease expires. */ if (!async_cancel(dsmp) || !async_start(dsmp, DHCP_EXTEND, B_FALSE) || !dhcp_extending(dsmp)) { if (monosec() + RETRY_DELAY < expiremax) { /* * Try again in RETRY_DELAY seconds; user command * should be gone. */ init_timer(&dlp->dl_t2, RETRY_DELAY); (void) set_smach_state(dsmp, oldstate); if (!schedule_lease_timer(dlp, &dlp->dl_t2, dhcp_rebind)) { dhcpmsg(MSG_INFO, "dhcp_rebind: unable to " "reschedule rebind around user command on " "%s; lease may expire", dsmp->dsm_name); } } else { dhcpmsg(MSG_WARNING, "dhcp_rebind: user busy on %s; " "will expire", dsmp->dsm_name); } } release_lease(dlp); }
void bootp(struct packet *packet) { struct host_decl *hp, *host = NULL; struct packet outgoing; struct dhcp_packet raw; struct sockaddr_in to; struct in_addr from; struct tree_cache *options[256]; struct subnet *subnet = NULL; struct lease *lease; struct iaddr ip_address; int i; if (packet->raw->op != BOOTREQUEST) return; note("BOOTREQUEST from %s via %s%s", print_hw_addr(packet->raw->htype, packet->raw->hlen, packet->raw->chaddr), packet->raw->giaddr.s_addr ? inet_ntoa(packet->raw->giaddr) : packet->interface->name, packet->options_valid ? "" : " (non-rfc1048)"); if (!locate_network(packet)) return; hp = find_hosts_by_haddr(packet->raw->htype, packet->raw->chaddr, packet->raw->hlen); lease = find_lease(packet, packet->shared_network, 0); /* * Find an IP address in the host_decl that matches the specified * network. */ if (hp) subnet = find_host_for_network(&hp, &ip_address, packet->shared_network); if (!subnet) { /* * We didn't find an applicable host declaration. Just in case * we may be able to dynamically assign an address, see if * there's a host declaration that doesn't have an ip address * associated with it. */ if (hp) for (; hp; hp = hp->n_ipaddr) if (!hp->fixed_addr) { host = hp; break; } if (host && (!host->group->allow_booting)) { note("Ignoring excluded BOOTP client %s", host->name ? host->name : print_hw_addr (packet->raw->htype, packet->raw->hlen, packet->raw->chaddr)); return; } if (host && (!host->group->allow_bootp)) { note("Ignoring BOOTP request from client %s", host->name ? host->name : print_hw_addr(packet->raw->htype, packet->raw->hlen, packet->raw->chaddr)); return; } /* * If we've been told not to boot unknown clients, and we didn't * find any host record for this client, ignore it. */ if (!host && !(packet->shared_network->group->boot_unknown_clients)) { note("Ignoring unknown BOOTP client %s via %s", print_hw_addr(packet->raw->htype, packet->raw->hlen, packet->raw->chaddr), packet->raw->giaddr.s_addr ? inet_ntoa(packet->raw->giaddr) : packet->interface->name); return; } /* * If we've been told not to boot with bootp on this network, * ignore it. */ if (!host && !(packet->shared_network->group->allow_bootp)) { note("Ignoring BOOTP request from client %s via %s", print_hw_addr(packet->raw->htype, packet->raw->hlen, packet->raw->chaddr), packet->raw->giaddr.s_addr ? inet_ntoa(packet->raw->giaddr) : packet->interface->name); return; } /* * If the packet is from a host we don't know and there are no * dynamic bootp addresses on the network it came in on, drop * it on the floor. */ if (!(packet->shared_network->group->dynamic_bootp)) { lose: note("No applicable record for BOOTP host %s via %s", print_hw_addr(packet->raw->htype, packet->raw->hlen, packet->raw->chaddr), packet->raw->giaddr.s_addr ? inet_ntoa(packet->raw->giaddr) : packet->interface->name); return; } /* * If a lease has already been assigned to this client and it's * still okay to use dynamic bootp on that lease, reassign it. */ if (lease) { /* * If this lease can be used for dynamic bootp, do so. */ if ((lease->flags & DYNAMIC_BOOTP_OK)) { /* * If it's not a DYNAMIC_BOOTP lease, release it * before reassigning it so that we don't get a * lease conflict. */ if (!(lease->flags & BOOTP_LEASE)) release_lease(lease); lease->host = host; ack_lease(packet, lease, 0, 0); return; } /* * If dynamic BOOTP is no longer allowed for this * lease, set it free. */ release_lease(lease); } /* * If there are dynamic bootp addresses that might be * available, try to snag one. */ for (lease = packet->shared_network->last_lease; lease && lease->ends <= cur_time; lease = lease->prev) { if ((lease->flags & DYNAMIC_BOOTP_OK)) { lease->host = host; ack_lease(packet, lease, 0, 0); return; } } goto lose; } /* Make sure we're allowed to boot this client. */ if (hp && (!hp->group->allow_booting)) { note("Ignoring excluded BOOTP client %s", hp->name); return; } /* Make sure we're allowed to boot this client with bootp. */ if (hp && (!hp->group->allow_bootp)) { note("Ignoring BOOTP request from client %s", hp->name); return; } /* Set up the outgoing packet... */ memset(&outgoing, 0, sizeof outgoing); memset(&raw, 0, sizeof raw); outgoing.raw = &raw; /* * If we didn't get a known vendor magic number on the way in, just * copy the input options to the output. */ if (!packet->options_valid && !subnet->group->always_reply_rfc1048 && (!hp || !hp->group->always_reply_rfc1048)) { memcpy(outgoing.raw->options, packet->raw->options, DHCP_OPTION_LEN); outgoing.packet_length = BOOTP_MIN_LEN; } else { struct tree_cache netmask_tree; /* -- RBF */ /* * Come up with a list of options that we want to send to this * client. Start with the per-subnet options, and then override * those with client-specific options. */ memcpy(options, subnet->group->options, sizeof(options)); for (i = 0; i < 256; i++) if (hp->group->options[i]) options[i] = hp->group->options[i]; /* * Use the subnet mask from the subnet declaration if no other * mask has been provided. */ if (!options[DHO_SUBNET_MASK]) { options[DHO_SUBNET_MASK] = &netmask_tree; netmask_tree.flags = TC_TEMPORARY; netmask_tree.value = lease->subnet->netmask.iabuf; netmask_tree.len = lease->subnet->netmask.len; netmask_tree.buf_size = lease->subnet->netmask.len; netmask_tree.timeout = -1; netmask_tree.tree = NULL; } /* * Pack the options into the buffer. Unlike DHCP, we can't pack * options into the filename and server name buffers. */ outgoing.packet_length = cons_options(packet, outgoing.raw, 0, options, 0, 0, 1, NULL, 0); if (outgoing.packet_length < BOOTP_MIN_LEN) outgoing.packet_length = BOOTP_MIN_LEN; } /* Take the fields that we care about... */ raw.op = BOOTREPLY; raw.htype = packet->raw->htype; raw.hlen = packet->raw->hlen; memcpy(raw.chaddr, packet->raw->chaddr, sizeof(raw.chaddr)); raw.hops = packet->raw->hops; raw.xid = packet->raw->xid; raw.secs = packet->raw->secs; raw.flags = packet->raw->flags; raw.ciaddr = packet->raw->ciaddr; memcpy(&raw.yiaddr, ip_address.iabuf, sizeof(raw.yiaddr)); /* Figure out the address of the next server. */ if (hp && hp->group->next_server.len) memcpy(&raw.siaddr, hp->group->next_server.iabuf, 4); else if (subnet->group->next_server.len) memcpy(&raw.siaddr, subnet->group->next_server.iabuf, 4); else if (subnet->interface_address.len) memcpy(&raw.siaddr, subnet->interface_address.iabuf, 4); else raw.siaddr = packet->interface->primary_address; raw.giaddr = packet->raw->giaddr; if (hp->group->server_name) strncpy(raw.sname, hp->group->server_name, sizeof(raw.sname)); else if (subnet->group->server_name) strncpy(raw.sname, subnet->group->server_name, sizeof(raw.sname)); if (hp->group->filename) strncpy(raw.file, hp->group->filename, sizeof(raw.file)); else if (subnet->group->filename) strncpy(raw.file, subnet->group->filename, sizeof(raw.file)); else memcpy(raw.file, packet->raw->file, sizeof(raw.file)); from = packet->interface->primary_address; /* Report what we're doing... */ note("BOOTREPLY for %s to %s (%s) via %s", piaddr(ip_address), hp->name, print_hw_addr(packet->raw->htype, packet->raw->hlen, packet->raw->chaddr), packet->raw->giaddr.s_addr ? inet_ntoa(packet->raw->giaddr) : packet->interface->name); /* Set up the parts of the address that are in common. */ memset(&to, 0, sizeof(to)); to.sin_family = AF_INET; #ifdef HAVE_SA_LEN to.sin_len = sizeof(to); #endif /* If this was gatewayed, send it back to the gateway... */ if (raw.giaddr.s_addr) { to.sin_addr = raw.giaddr; to.sin_port = server_port; (void) send_packet(packet->interface, &raw, outgoing.packet_length, from, &to, packet->haddr); return; } /* * If it comes from a client that already knows its address and is not * requesting a broadcast response, and we can unicast to a client * without using the ARP protocol, sent it directly to that client. */ else if (!(raw.flags & htons(BOOTP_BROADCAST))) { to.sin_addr = raw.yiaddr; to.sin_port = client_port; } else { /* Otherwise, broadcast it on the local network. */ to.sin_addr.s_addr = INADDR_BROADCAST; to.sin_port = client_port; /* XXX */ } errno = 0; (void) send_packet(packet->interface, &raw, outgoing.packet_length, from, &to, packet->haddr); }