interface.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.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/if_ether.h>
#include <signal.h>
#include <dhcpmsg.h>
#include <libdevinfo.h>
#include "interface.h"
#include "util.h"
#include "dlpi_io.h"
#include "packet.h"
#include "defaults.h"
#include "states.h"
#include "script_handler.h"
/*
* note to the reader:
*
* the terminology in here is slightly confusing. in particular, the
* term `ifslist' is used to refer both to the `struct ifslist' entry
* that makes up a specific interface entry, and the `internal
* ifslist' which is a linked list of struct ifslists. to reduce
* confusion, in the comments, a `struct ifslist' is referred to as
* an `ifs', and `ifslist' refers to the internal ifslist.
*
*/
static unsigned int ifscount;
static void cancel_ifs_timer(struct ifslist *, int);
unsigned int *);
/*
* insert_ifs(): creates a new ifs and chains it on the ifslist. initializes
* state which remains consistent across all use of the ifs entry
*
* input: const char *: the name of the ifs entry (interface name)
* boolean_t: if B_TRUE, we're adopting the interface
* int *: ignored on input; if insert_ifs fails, set to a DHCP_IPC_E_*
* error code with the reason why
* output: struct ifslist *: a pointer to the new ifs entry, or NULL on failure
*/
struct ifslist *
{
unsigned int i, client_id_len = 0;
const char *prl;
long seed;
return (NULL);
}
/*
* okay, we've got a request to put a new interface under our
* control. it's our job to set everything that doesn't
* change for the life of the interface. (state that changes
* should be initialized in init_ifs() and reset by reset_ifs())
*
* 1. verify the interface can support DHCP
* 2. get the interface mtu
* 3. get the interface hardware type and hardware length
* 4. get the interface hardware address
* 5. get the interface broadcast address
* 6. get the interface flags
*/
"%s", if_name);
return (NULL);
}
/* step 1 */
goto failure;
}
/* step 2 */
"enough maximum SDU to support DHCP", if_name);
goto failure;
}
/* step 3 */
/* step 4 */
"for %s", if_name);
goto failure;
}
/*
* depending on the DLPI device, the sap and hardware addresses
* can be in either order within the dlsap address; find the
* location of the hardware address using dl_sap_length. see the
* DLPI specification for more on this braindamage.
*/
if (dlia->dl_sap_length > 0) {
ifsp->if_sap_before++;
}
/* step 5 */
"for %s", if_name);
goto failure;
}
/* step 6 */
else
*error = DHCP_IPC_E_INT;
goto failure;
}
/*
* if DHCPRUNNING is already set on the interface and we're
* not adopting it, the agent probably crashed and burned.
* note it, but don't let it stop the proceedings. we're
* pretty sure we're not already running, since we wouldn't
* have been able to bind to our IPC port.
*/
if_name);
"for %s", if_name);
goto failure;
}
if (is_adopting) {
/*
* if the agent is adopting a lease OBP is initially
* searched for a client-id
*/
"property");
&client_id_len)) {
/*
* a failure occurred trying to acquire the client-id
*/
"id for %s", if_name);
*error = DHCP_IPC_E_INT;
goto failure;
/*
* when the interface is infiniband and the agent
* is adopting the lease there must be an OBP
* client-id.
*/
"id for %s", if_name);
*error = DHCP_IPC_E_INT;
goto failure;
}
} else {
/*
* look in defaults file for the client-id
*/
"property");
/*
* at this point, all logical interfaces must be explicitly
* configured with a client id by the administrator.
*/
"logical interface %s; cannot manage", if_name);
goto failure;
}
/*
* the defaults client-id value must be copied out to
* another buffer
*/
"allocate client id for %s", if_name);
goto failure;
}
/*
* This comes from DHCP over IPoIB spec. In the absence
* of an user specified client id, IPoIB automatically
* uses the required format, with the unique 4 octet
* value set to 0 (since IPoIB driver allows only a
* single interface on a port with a specific GID to
* belong to an IP subnet (PSARC 2001/289,
* FWARC 2002/702).
*
* Type Client-Identifier
* +-----+-----+-----+-----+-----+----....----+
* | 0 | 0 (4 octets) | GID (16 octets)|
* +-----+-----+-----+-----+-----+----....----+
*/
"allocate client id for %s", if_name);
goto failure;
}
/*
* Pick the GID from the mac address. The format
* of the hardware address is:
* +-----+-----+-----+-----+----....----+
* | QPN (4 octets) | GID (16 octets)|
* +-----+-----+-----+-----+----....----+
*/
}
}
/*
* initialize the parameter request list, if there is one.
*/
else {
if (prl[i] == ',')
"parameter request list for %s (continuing)",
if_name);
} else {
prl++;
if (*prl == '\0')
break;
}
}
}
/*
* we're past the point of failure; chain it on.
*/
ifscount++;
if (inactivity_id != -1) {
inactivity_id = -1;
}
/*
* seed the random number generator, since we're going to need it
* to set transaction id's and for exponential backoff. if an
* interface is already initialized, then we just end up harmlessly
* reseeding it. note that we try to spread the hardware address
* over as many bits of the seed as possible.
*/
return (ifsp);
return (NULL);
}
/*
* init_ifs(): puts an ifs in its initial state
*
* input: struct ifslist *: the ifs to initialize
* output: void
* note: if the interface isn't fresh, use reset_ifs()
*/
static void
{
/*
* if_sock_ip_fd is created and bound in configure_if().
* if_sock_fd is bound in configure_if(); see comments in
* bound.c for more details on why. if creation of if_sock_fd
* fails, we'll need more context anyway, so don't check.
*/
ifsp->if_nrouters = 0;
}
/*
* remove_ifs_default_routes(): removes an ifs's default routes
*
* input: struct ifslist *: the ifs whose default routes need to be removed
* output: void
*/
static void
{
while (ifsp->if_nrouters > 0) {
}
}
}
/*
* reset_ifs(): resets an ifs to its initial state
*
* input: struct ifslist *: the ifs to reset
* output: void
*/
void
{
(void) release_ifs(ifsp);
}
}
/*
* lookup_ifs(): looks up an ifs, given its name
*
* input: const char *: the name of the ifs entry (the interface name)
* the name "" searches for the primary interface
* output: struct ifslist *: the corresponding ifs, or NULL if not found
*/
struct ifslist *
lookup_ifs(const char *if_name)
{
if (*if_name != '\0') {
break;
break;
return (ifs);
}
/*
* lookup_ifs_by_xid(): looks up an ifs, given its last used transaction id
*
* input: int: the transaction id to look up
* output: struct ifslist *: the corresponding ifs, or NULL if not found
*/
struct ifslist *
{
break;
}
return (ifs);
}
/*
* remove_ifs(): removes a given ifs from the ifslist. marks the ifs
* for being freed (but may not actually free it).
*
* input: struct ifslist *: the ifs to remove
* output: void
* note: see interface.h for a discussion of ifs memory management
*/
void
{
return;
}
/*
* if we have long term timers, cancel them so that interface
* resources can be reclaimed in a reasonable amount of time.
*/
else
ifscount--;
(void) release_ifs(ifsp);
/* no big deal if this fails */
if (ifscount == 0) {
}
}
/*
* hold_ifs(): acquires a hold on an ifs
*
* input: struct ifslist *: the ifs entry to acquire a hold on
* output: void
*/
void
{
ifsp->if_hold_count++;
}
/*
* release_ifs(): releases a hold previously acquired on an ifs. if the
* hold count reaches 0, the ifs is freed
*
* input: struct ifslist *: the ifs entry to release the hold on
* output: int: the number of holds outstanding on the ifs
*/
int
{
if (ifsp->if_hold_count == 0) {
return (0);
}
if (--ifsp->if_hold_count == 0) {
return (0);
}
return (ifsp->if_hold_count);
}
/*
* free_ifs(): frees the memory occupied by an ifs entry
*
* input: struct ifslist *: the ifs entry to free
* output: void
*/
static void
{
}
/*
* checkaddr(): checks if the given address is still set on the given ifs
*
* input: struct ifslist *: the ifs to check
* int: the address to lookup on the interface
* struct in_addr *: the address to compare to
* output: boolean_t: B_TRUE if the address is still set; B_FALSE if not
*/
static boolean_t
{
struct sockaddr_in *sin;
/* LINTED [ifr_addr is a sockaddr which will be aligned] */
case 0:
return (B_FALSE);
break;
case -1:
return (B_FALSE);
break;
}
return (B_TRUE);
}
/*
* verify_ifs(): verifies than an ifs is still valid (i.e., has not been
* explicitly or implicitly dropped or released)
*
* input: struct ifslist *: the ifs to verify
* output: int: 1 if the ifs is still valid, 0 if the interface is invalid
*/
int
{
return (0);
case BOUND:
case RENEWING:
case REBINDING:
/*
* if the interface has gone down or been unplumbed, then we
* act like there has been an implicit drop.
*/
case 0:
goto abandon;
break;
case -1:
goto abandon;
break;
}
/* FALLTHRU */
case INIT_REBOOT:
case SELECTING:
case REQUESTING:
/*
* if the IP address, netmask, or broadcast address have
* changed, or the interface has been unplumbed, then we act
* like there has been an implicit drop.
*/
goto abandon;
}
return (1);
return (0);
}
/*
* canonize_ifs(): puts the interface in a canonical (zeroed) form
*
* input: struct ifslist *: the interface to canonize
* output: int: 1 on success, 0 on failure
*/
int
{
struct sockaddr_in *sin;
/*
* note that due to infelicities in the routing code, any default
* routes must be removed prior to clearing the UP flag.
*/
/* LINTED [ifr_addr is a sockaddr which will be aligned] */
return (0);
/*
* clear the UP flag, but don't clear DHCPRUNNING since
* that should only be done when the interface is removed
* (see remove_ifs())
*/
return (0);
/*
* since ifr is actually a union, we need to explicitly zero
* the flags field before we reuse the structure, or otherwise
* cruft may leak over into other members of the union.
*/
return (0);
return (0);
return (0);
/*
* any time we change the IP address, netmask, or broadcast we
* must be careful to also reset bookkeeping of what these are
* set to. this is so we can detect if these characteristics
* are changed by another process.
*/
return (1);
}
/*
* check_ifs(): makes sure an ifs is still valid, and if it is, releases the
* ifs. otherwise, it informs the caller the ifs is going away
* and expects the caller to perform the release
*
* input: struct ifslist *: the ifs to check
* output: int: 1 if the interface is valid, 0 otherwise
*/
int
{
/*
* this interface is going away. if there's an
* uncancelled IPC event roaming around, cancel it
* now. we leave the hold on in case anyone else has
* any cleanup work that needs to be done before the
* interface goes away.
*/
return (0);
}
(void) release_ifs(ifsp);
return (1);
}
/*
* nuke_ifslist(): delete the ifslist (for use when the dhcpagent is exiting)
*
* input: boolean_t: B_TRUE if the agent is exiting due to SIGTERM
* output: void
*/
void
{
int status;
/* stop a script if it is not for DROP or RELEASE */
continue;
}
}
/*
* if the script is started by script_start, dhcp_drop and
* dhcp_release should and will only be called after the
* script exits.
*/
if (onterm &&
continue;
}
if (status == 1)
continue;
}
}
}
/*
* refresh_ifslist(): refreshes all finite leases under DHCP control
*
* input: iu_eh_t *: unused
* int: unused
* void *: unused
* output: void
*/
/* ARGSUSED */
void
{
continue;
continue;
/*
* this interface has a finite lease and we do not know
* how long the machine's been off for. refresh it.
*/
}
}
/*
* ifs_count(): returns the number of interfaces currently managed
*
* input: void
* output: unsigned int: the number of interfaces currently managed
*/
unsigned int
ifs_count(void)
{
return (ifscount);
}
/*
* cancel_ifs_timer(): cancels a lease-related timer on an interface
*
* input: struct ifslist *: the interface to operate on
* int: the timer id of the timer to cancel
* output: void
*/
static void
{
(void) release_ifs(ifsp);
} else
"if_timer[%d]", timer_id);
}
}
/*
* cancel_ifs_timers(): cancels an interface's pending lease-related timers
*
* input: struct ifslist *: the interface to operate on
* output: void
*/
void
{
}
/*
* schedule_ifs_timer(): schedules a lease-related timer on an interface
*
* input: struct ifslist *: the interface to operate on
* int: the timer to schedule
* uint32_t: the number of seconds in the future it should fire
* iu_tq_callback_t *: the callback to call upon firing
* output: int: 1 if the timer was scheduled successfully, 0 on failure
*/
int
{
"if_timer[%d]", timer_id);
return (0);
}
return (1);
}
/*
* Get the value of the named property on the named node in devinfo root.
*
* input: const char *: The name of the node containing the property.
* const char *: The name of the property.
* uchar_t **: The property value, modified iff B_TRUE is returned.
* If no value is found the value is set to NULL.
* unsigned int *: The length of the property value
* output: boolean_t: Returns B_TRUE if successful (no problems),
* otherwise B_FALSE.
* note: The memory allocated by this function must be freed by
* the caller. This code is derived from
*/
static boolean_t
unsigned int *lenp)
{
unsigned int len = 0;
/*
* locate root node
*/
"not found");
goto get_prom_prop_cleanup;
}
/*
* locate nodename within '/'
*/
node != DI_NODE_NIL;
break;
}
}
if (node == DI_NODE_NIL) {
goto get_prom_prop_cleanup;
}
/*
* scan all properties of /nodename for the 'propname' property
*/
pp != DI_PROM_PROP_NIL;
break;
}
}
if (pp == DI_PROM_PROP_NIL) {
goto get_prom_prop_cleanup;
}
/*
* get the property; allocate some memory copy it out
*/
/*
* property data read problems
*/
goto get_prom_prop_cleanup;
}
if (propvaluep != NULL) {
/*
* allocate somewhere to copy the property value to
*/
if (*propvaluep == NULL) {
/*
* allocation problems
*/
"memory for property value");
goto get_prom_prop_cleanup;
}
/*
* copy data out
*/
/*
* copy out the length if a suitable pointer has
* been supplied
*/
}
"length = %d", len);
}
if (phdl != DI_PROM_HANDLE_NIL) {
}
if (root_node != DI_NODE_NIL) {
}
return (success);
}