request.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* REQUESTING state of the client state machine.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <dhcp_hostconf.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <dhcpmsg.h>
#include "states.h"
#include "util.h"
#include "packet.h"
#include "interface.h"
#include "agent.h"
#include "defaults.h"
static void restart_dhcp(struct ifslist *);
static stop_func_t stop_requesting;
/*
* dhcp_requesting(): checks if OFFER packets to come in from DHCP servers.
* if so, chooses the best one, sends a REQUEST to the
* server and registers an event handler to receive
*
* input: iu_tq_t *: unused
* void *: the interface receiving OFFER packets
* output: void
*/
/* ARGSUSED */
void
{
(void) release_ifs(ifsp);
return;
}
/*
* select the best OFFER; all others pitched.
*/
/*
* no acceptable OFFERs have come in. reschedule
* ourselves for callback.
*/
/*
* ugh. the best we can do at this point is
* revert back to INIT and wait for a user to
* restart us.
*/
"reschedule callback, reverting to INIT state on "
} else
return;
}
/*
* stop collecting packets. check to see whether we got an
* OFFER or a BOOTP packet. if we got a BOOTP packet, go to
* the BOUND state now.
*/
(void) release_ifs(ifsp);
}
return;
}
return;
}
/*
* if we got a message from the server, display it.
*/
/*
* assemble a DHCPREQUEST, with the ciaddr field set to 0,
* since we got here from the INIT state.
*/
/*
* grab the lease out of the OFFER; we know it's valid since
* select_best() already checked. The max dhcp message size
* option is set to the interface max, minus the size of the udp and
* ip headers.
*/
sizeof (lease_t));
sizeof (struct udpiphdr)));
/*
* if_reqhost was set for this interface in dhcp_selecting()
* if the DF_REQUEST_HOSTNAME option set and a host name was
* found
*/
}
/* all done with the offer */
/*
* send out the REQUEST, trying retransmissions. either a NAK
* or too many REQUEST attempts will revert us to SELECTING.
*/
/*
* wait for an ACK or NAK to come back from the server. if
* we can't register this event handler, then we won't be able
* to see the server's responses. the best we can really do
* in that case is drop back to INIT and hope someone notices.
*/
if (register_acknak(ifsp) == 0) {
}
}
/*
* select_best(): selects the best OFFER packet from a list of OFFER packets
*
* input: PKT_LIST **: a list of packets to select the best from
* output: PKT_LIST *: the best packet, or NULL if none are acceptable
*/
static PKT_LIST *
{
/*
* pick out the best offer. point system.
* what's important?
*
* 0) DHCP
* 1) no option overload
* 2) encapsulated vendor option
* 3) non-null sname and siaddr fields
* 4) non-null file field
* 5) hostname
* 6) subnetmask
* 7) router
*/
points = 0;
goto valid_offer;
}
"lease time");
continue;
}
"lease time");
continue;
}
"server id");
continue;
}
"server id");
continue;
}
/* valid DHCP OFFER. see if we got our parameters. */
points += 30;
points += 5;
/*
* also could be faked, though more difficult because
* the encapsulation is hard to encode on a BOOTP
* server; plus there's not as much real estate in the
* packet for options, so it's likely this option
* would get dropped.
*/
points += 80;
points++;
points++;
points += 5;
if (points >= best_points) {
}
}
} else
return (best);
}
/*
* dhcp_acknak(): processes reception of an ACK or NAK packet on an interface
*
* input: iu_eh_t *: unused
* short: unused
* iu_event_id_t: the id of this event callback with the handler
* void *: the interface that received the ACK or NAK
* output: void
*/
/* ARGSUSED */
void
{
/* unregister_acknak() does our release_ifs() */
(void) unregister_acknak(ifsp);
return;
}
/*
* note that check_ifs() did our release_ifs() but we're not
* sure we're done yet; call hold_ifs() to reacquire our hold;
* if we're done, unregister_acknak() will release_ifs() below.
*/
return;
/*
* we've got a packet; make sure it's acceptable before
* cancelling the REQUEST retransmissions.
*/
"missing mandatory lease option, ignored",
ifsp->if_bad_offers++;
free_pkt_list(&plp);
return;
}
"has a different IP address (%s), ignored",
ifsp->if_bad_offers++;
free_pkt_list(&plp);
return;
}
}
/*
* looks good; cancel the retransmission timer and unregister
* the acknak handler. ACK to BOUND, NAK back to SELECTING.
*/
(void) unregister_acknak(ifsp);
ifsp->if_bad_offers++;
free_pkt_list(&plp);
/*
* remove any bogus cached configuration we might have
* around (right now would only happen if we got here
* from INIT_REBOOT).
*/
return;
}
ifsp->if_bad_offers++;
free_pkt_list(&plp);
return;
}
return;
}
}
/*
* restart_dhcp(): restarts DHCP (from INIT) on a given interface
*
* input: struct ifslist *: the interface to restart DHCP on
* output: void
*/
static void
{
} else
}
/*
* stop_requesting(): decides when to stop retransmitting REQUESTs
*
* input: struct ifslist *: the interface REQUESTs are being sent on
* unsigned int: the number of REQUESTs sent so far
* output: boolean_t: B_TRUE if retransmissions should stop
*/
static boolean_t
{
if (n_requests >= DHCP_MAX_REQUESTS) {
(void) unregister_acknak(ifsp);
return (B_TRUE);
}
return (B_FALSE);
}