diff options
Diffstat (limited to 'server/dhcp.c')
-rw-r--r-- | server/dhcp.c | 200 |
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 (<, 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, <); + + /* Send a response to the client... */ + dump_subnets (); } |