generic.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
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* This file contains routines that are shared between the DHCP server
* implementation and BOOTP server compatibility.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <stdarg.h>
#include <errno.h>
#include <alloca.h>
#include <string.h>
#include <netdb.h>
#include <search.h>
#include <dhcp_symbol.h>
#include "dhcpd.h"
#include "per_dnet.h"
#include "interfaces.h"
#include <locale.h>
#include <resolv.h>
/*
* Get the client id. Sets cid and len.
*/
void
{
/*
* If the DHCP client specified the client id option, use that,
* otherwise use the client's hardware type and hardware address.
*/
/* DHCP client w/ client id */
else
} else {
/* BOOTP client or DHCP client w/o client id. */
}
}
/*
* Return a string representing an ASCII version of the client_id.
*/
char *
{
} else {
}
return (bufp);
}
/*
* Based on the contents of the PKT_LIST structure for an incoming
* packet, determine the net address and subnet mask identifying the
* dhcp-network database. This centralizes choices that were formerly
* made in the specific protocol routines.
*/
void
{
/*
* For BOOTP, REQUEST, RELEASE, and INFORM packets, trust client's
* notion of IP address if ciaddr is set. Use it to figure out correct
* dhcp-network.
*/
/*
* Calculate client's default net mask, consult netmasks
* database to see if net is further subnetted. Use resulting
* subnet mask with client's address to produce dhcp-network
* database name.
*/
} else
/*
* If no trusted IP address, examine giaddr.
*/
/*
* Packet received thru a relay agent. Calculate the
* net's address using subnet mask and giaddr.
*/
} else {
/* Locally connected net. */
}
}
}
struct netmask_node;
typedef struct netmask_node {
} NNODE;
static void *nroot; /* root of netmask tree */
/*
*/
static int
{
}
/*
* Given a network-order address, calculate client's default net mask.
* Consult local cache, then netmasks database to see if net is further
* subnetted. We'll only snag the first netmask that matches our criteria.
*/
void
{
/*
* First check locally maintained, incomplete cache.
*/
(void) rw_rdlock(&nroot_rwlock);
/* Delete expired tree. */
(void) rw_unlock(&nroot_rwlock);
(void) rw_wrlock(&nroot_rwlock);
}
} else {
(void) rw_unlock(&nroot_rwlock);
return;
}
}
}
/*
* Note: workaround for 4336124: single-thread access to
* nss search routines to avoid getting incorrect results.
*/
/* Convert to and from host order. */
/* While inserting check that another insert has not occurred. */
(void) rw_unlock(&nroot_rwlock);
}
/*
* This function is charged with loading the options field with the
* small to fit the options, then option overload is enabled.
*
* Note that the caller is expected to free any allocated ENCODE lists,
* with the exception of locally-allocated lists in the case where ecp is
* NULL, but vecp is not. In this case, the resultant ecp list (ecp == tvep)
* is freed locally.
*
* Returns: The actual size of the utilized packet buffer.
*/
int
{
/*
* We handle vendor options by fabricating an ENCODE of type
* CD_VENDOR_SPEC, and setting its datafield equal to vecp.
*
* We assume we've been handed the proper class list.
*/
vend_len = 0;
if (vend_len != 0) {
"Warning: Too much vendor data (> 255) to "
"encapsulate within option %d.\n",
}
}
/* this make_encode *doesn't* copy data */
/* Tack it on the end of standard list. */
else
}
}
/*
* Scan the options first to determine if we could potentially
* option overload.
*/
if (flags & DHCP_DHCP_CLNT) {
case CD_SNAME:
break;
case CD_BOOTFILE:
break;
}
}
} else
/*
* simply echo back client's boot file, and don't overload.
* if CD_BOOTPATH is set, we'll simply rewrite the r_pktp
* file field to include it along with the client's requested
* name during the load pass through the internal options.
* Here we let the overload code know we're not to overload
* the file field.
*/
} else
/* Now actually load the options! */
/*
* non rfc1048 clients can only get packet fields and
* the CD_BOOTPATH internal pseudo opt, which only potentially
* affects the file field.
*/
if ((flags & DHCP_NON_RFC1048) &&
code == CD_BOOTPATH))) {
continue;
}
if ((flags & DHCP_SEND_LEASE) == 0 &&
cat == DSYM_STANDARD &&
code == CD_LEASE_TIME)) {
continue;
}
/* standard and site options */
cat == DSYM_VENDOR) {
/*
* This horrible kludge is necessary because the DHCP
* options RFCs require that the subnet option MUST
* precede the router option. To accomplish this, we
*
* inspect each of the standard options, waiting
* for CD_ROUTER to turn up (if it never does,
* no special handling is needed)
*
* search the remaining options for CD_SUBNETMASK
* If it occurs, we
* set router_ecp to indicate where to find
* the router option's values that we have
* not yet emitted
*
* reinitialize code, len, and data to emit
* the CD_SUBNETMASK option now
*
* when CD_SUBNETMASK is encountered, we
* reinitialize code, len, and data to emit
* the CD_ROUTER option
*/
router_ecp = ep;
}
} else if ((cat == DSYM_STANDARD) &&
}
/*
* Keep an eye on option field. Option overload. Note
* that we need to keep track of the space necessary
* to place the Overload option in the options section
* (that's the 3 octets below.) The 2 octets cover the
* necessary code and len portion of the payload.
*/
if (using_overload == DHCP_OVRLD_CLR) {
} else {
}
/*
* If overload is not possible, we will
* keep going, hoping to find an option
* that will fit in the remaining space,
* rather than just give up.
*/
if (using_overload == DHCP_OVRLD_CLR) {
*optp++ = CD_OPTION_OVERLOAD;
*optp++ = 1;
} else {
}
}
switch (overload) {
case DHCP_OVRLD_CLR:
/* great, can use both */
/* FALLTHRU */
case DHCP_OVRLD_FILE:
/* Can use sname. */
break;
case DHCP_OVRLD_SNAME:
/* Using sname, can use file. */
break;
}
} else {
/* Load options. */
}
} else if (cat == DSYM_FIELD) {
/* packet field pseudo options */
switch (code) {
case CD_SIADDR:
/*
* Configuration includes Boot server addr
*/
len);
break;
case CD_SNAME:
/*
* Configuration includes Boot server name
*/
break;
case CD_BOOTFILE:
/*
* Configuration includes boot file.
* Always authoritative.
*/
break;
default:
"Unsettable DHCP packet field: %d\n", code);
break;
}
} else if (cat == DSYM_INTERNAL) {
/* Internal server pseudo options */
switch (code) {
case CD_BOOTPATH:
/*
* Prefix for boot file. Only used if
* client provides bootfile and server doesn't
* specify one. Prepended on client's bootfile
* value. Otherwise ignored.
*/
if (echo_clnt_file) {
flen++;
else
flen);
"BootPath(%1$s) + "
"BootFile(%2$s) too "
"long: %3$d > %4$d\n",
} else {
(void) memcpy(
}
}
break;
case CD_BOOL_HOSTNAME:
/* FALLTHRU */
case CD_BOOL_LEASENEG:
/* FALLTHRU */
case CD_BOOL_ECHO_VCLASS:
/*
* These pseudo opts have had their
* affect elsewhere, such as dhcp.c.
*/
break;
default:
"Unknown Internal pseudo opt: %d\n", code);
break;
}
} else {
"Unrecognized option with code: %d %d\n", cat,
code);
}
}
if (using_overload != DHCP_OVRLD_CLR) {
*main_optp++ = using_overload;
} else
}
/*
* Reinitialize the dhcptab database, as a result of timeout or
* user signal. Note: if_head_mtx cannot be held by caller.
*/
void *
reinitialize(void *arg)
{
int totpkts;
int err;
/*
* Got a signal to reinitialize
*/
if (verbose)
if (!no_dhcptab) {
if (checktab() != 0) {
"WARNING: Cannot access dhcptab.\n");
} else {
"Error reading dhcptab.\n");
return ((void *)err);
}
}
}
/*
* Drop all pending offers, display interface statistics.
*/
if (verbose) {
(void) mutex_lock(&if_head_mtx);
}
(void) mutex_unlock(&if_head_mtx);
"Total Packets received on all interfaces: %d\n", totpkts);
}
/* Default domain may have changed */
/* Release reinitialization thread */
return (NULL);
}