summaryrefslogtreecommitdiff
path: root/server/dhcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'server/dhcp.c')
-rw-r--r--server/dhcp.c200
1 files changed, 200 insertions, 0 deletions
diff --git a/server/dhcp.c b/server/dhcp.c
index fa49eccc..640c726f 100644
--- a/server/dhcp.c
+++ b/server/dhcp.c
@@ -49,5 +49,205 @@ static char copyright[] =
void dhcp (packet)
struct packet *packet;
{
+ struct lease *uid_lease, *ip_lease, *hw_lease, *lease;
+ struct iaddr cip;
+ struct lease lt;
+ TIME lease_time;
+
dump_packet (packet);
+
+ /* Try to find a lease that's been assigned to the specified
+ unique client identifier. */
+ if (packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len)
+ uid_lease =
+ find_lease_by_uid (packet -> options
+ [DHO_DHCP_CLIENT_IDENTIFIER].data,
+ packet -> options
+ [DHO_DHCP_CLIENT_IDENTIFIER].len);
+ else
+ uid_lease = (struct lease *)0;
+
+ /* Try to find a lease that's been attached to the client's
+ hardware address... */
+ hw_lease = find_lease_by_hw_addr (packet -> raw -> chaddr,
+ packet -> raw -> hlen);
+
+ /* Try to find a lease that's been allocated to the client's
+ IP address. */
+ if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len &&
+ packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len
+ <= sizeof cip.iabuf) {
+ cip.len = packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len;
+ memcpy (cip.iabuf,
+ packet -> options [DHO_DHCP_REQUESTED_ADDRESS].data,
+ packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len);
+ memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);
+ ip_lease = find_lease_by_ip_addr (cip);
+ } else
+ ip_lease = (struct lease *)0;
+
+ printf ("First blush:\n");
+ if (ip_lease) {
+ printf ("ip_lease: ");
+ print_lease (ip_lease);
+ }
+ if (hw_lease) {
+ printf ("hw_lease: ");
+ print_lease (hw_lease);
+ }
+ if (uid_lease) {
+ printf ("uid_lease: ");
+ print_lease (uid_lease);
+ }
+
+ /* Toss extra pointers to the same lease... */
+ if (ip_lease == hw_lease)
+ ip_lease = (struct lease *)0;
+ if (hw_lease == uid_lease)
+ hw_lease = (struct lease *)0;
+ if (ip_lease == uid_lease)
+ ip_lease = (struct lease *)0;
+
+ printf ("Second blush:\n");
+ if (ip_lease) {
+ printf ("ip_lease: ");
+ print_lease (ip_lease);
+ }
+ if (hw_lease) {
+ printf ("hw_lease: ");
+ print_lease (hw_lease);
+ }
+ if (uid_lease) {
+ printf ("uid_lease: ");
+ print_lease (uid_lease);
+ }
+
+ /* If we got an ip address lease, make sure it isn't assigned to
+ some *other* client! If it was assigned to this client, we'd
+ have zeroed it out above, so the only way we can take it at this
+ point is if some other client had it but it's timed out, or if no
+ other client has ever had it. */
+ if (ip_lease &&
+ ip_lease -> ends >= cur_time)
+ ip_lease = (struct lease *)0;
+
+ /* Now eliminate leases that are on the wrong subnet... */
+ if (ip_lease && packet -> subnet != ip_lease -> contain) {
+ release_lease (ip_lease);
+ ip_lease = (struct lease *)0;
+ }
+ if (uid_lease && packet -> subnet != uid_lease -> contain) {
+ release_lease (uid_lease);
+ uid_lease = (struct lease *)0;
+ }
+ if (hw_lease && packet -> subnet != hw_lease -> contain) {
+ release_lease (hw_lease);
+ hw_lease = (struct lease *)0;
+ }
+
+ printf ("Third blush:\n");
+ if (ip_lease) {
+ printf ("ip_lease: ");
+ print_lease (ip_lease);
+ }
+ if (hw_lease) {
+ printf ("hw_lease: ");
+ print_lease (hw_lease);
+ }
+ if (uid_lease) {
+ printf ("uid_lease: ");
+ print_lease (uid_lease);
+ }
+
+ /* At this point, if ip_lease is nonzero, we can assign it to
+ this client. */
+ lease = ip_lease;
+
+ /* If we got a lease that matched the client identifier, we may want
+ to use it, but if we already have a lease we like, we must free
+ the lease that matched the client identifier. */
+ if (uid_lease) {
+ if (lease) {
+ release_lease (uid_lease);
+ } else
+ lease = uid_lease;
+ }
+
+ /* The lease that matched the hardware address is treated likewise. */
+ if (hw_lease) {
+ if (lease) {
+ release_lease (hw_lease);
+ } else
+ lease = hw_lease;
+ }
+
+ /* If we didn't find a lease, try to allocate one... */
+ if (!lease) {
+ lease = packet -> subnet -> last_lease;
+
+ /* If there are no leases in that subnet that have
+ expired, we have nothing to offer this client. */
+ if (lease -> ends >= cur_time) {
+ note ("no free leases on subnet %s",
+ piaddr (packet -> subnet -> net));
+ return;
+ }
+ lease -> host = (struct host_decl *)0;
+ }
+
+ /* At this point, we have a lease that we can offer the client.
+ Now we construct a lease structure that contains what we want,
+ and call supersede_lease to do the right thing with it. */
+
+ memset (&lt, 0, sizeof lt);
+
+ /* Use the ip address of the lease that we finally found in
+ the database. */
+ lt.ip_addr = lease -> ip_addr;
+
+ /* Start now. */
+ lt.starts = cur_time;
+
+ /* Figure out how long a lease to assign. */
+ if (packet -> options [DHO_DHCP_LEASE_TIME].len == 4) {
+ lease_time = getULong (packet ->
+ options [DHO_DHCP_LEASE_TIME].data);
+
+ /* Don't let the client ask for a longer lease than
+ is supported for this subnet. */
+ if (lease_time > packet -> subnet -> max_lease_time)
+ lease_time = packet -> subnet -> max_lease_time;
+ } else
+ lease_time = packet -> subnet -> default_lease_time;
+ lt.ends = cur_time + lease_time;
+
+ lt.timestamp = cur_time;
+
+ /* Record the uid, if given... */
+ if (packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len) {
+ lt.uid_len =
+ packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len;
+ lt.uid = packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].data;
+ packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].data =
+ (unsigned char *)0;
+ packet -> options [DHO_DHCP_CLIENT_IDENTIFIER].len = 0;
+ }
+
+ /* Record the hardware address, if given... */
+ lt.hardware_addr.hlen = packet -> raw -> hlen;
+ lt.hardware_addr.htype = packet -> raw -> htype;
+ memcpy (lt.hardware_addr.haddr, packet -> raw -> chaddr,
+ packet -> raw -> hlen);
+
+ lt.host = lease -> host; /* XXX */
+ lt.contain = lease -> contain;
+
+ /* Record the transaction id... */
+ lt.xid = packet -> raw -> xid;
+
+ /* Install the new information about this lease in the database. */
+ supersede_lease (lease, &lt);
+
+ /* Send a response to the client... */
+ dump_subnets ();
}