www.pudn.com > bootpLib_for_VxWORKS.rar > bootpLib.c
/* bootpLib.c - BOOTP client library */
/* Copyright 1984 - 1999 Wind River Systems, Inc. */
#include "copyright_wrs.h"
/*
modification history
--------------------
01v,17mar99,spm added support for identical unit numbers (SPR #20913)
01u,04sep98,ham corrected lack of params for etherInputHookAdd(),SPR#21909
01t,28aug98,n_s corrected MAC address comparison in bootpInputHook. spr #20902
01s,17jul97,dgp doc: correct unsupported interfaces per SPR 8940
02c,14dec97,jdi doc: cleanup.
02b,10dec97,gnn making man page fixes
02a,08dec97,gnn END code review fixes
01z,03dec97,spm corrected parameter description for bootpMsgSend (SPR #9401);
minor changes to man pages and code spacing
01y,03oct97,gnn removed references to endDriver global.
01x,25sep97,gnn SENS beta feedback fixes
01w,26aug97,spm fixed bootpParamsGet - gateway not retrieved (SPR #9137)
01v,12aug97,gnn changes necessitated by MUX/END update.
01u,30apr97,jag man page edit for function bootParamsGet()
01t,07apr97,spm changed BOOTP interface to DHCP style: all options supported
01s,17dec96,gnn added code to handle the new etherHooks and END stuff.
01r,08nov96,spm Updated example of bootpParamsGet() for SPR 7120
01q,22sep96,spm Fixed SPR 7120: added support for gateways to bootpParamsGet()
01p,01feb96,gnn added the end of vendor data (0xff) to the request packet
we send
01o,16jan94,rhp fix typo in library man page
01n,17oct94,rhp remove docn reference to bootpdLib (SPR#2351)
01n,22sep92,jdi documentation cleanup.
01m,14aug92,elh documentation changes.
01l,11jun92,elh modified parameters to bootpParamsGet.
01k,26may92,rrr the tree shuffle
-changed includes to have absolute path from h/
01j,16apr92,elh moved routines shared by icmp to icmpLib.
01i,28feb92,elh ansified.
01h,27aug91,elh rewritten to use standard bootp protocol,
redesigned to be more modular, rewrote documentation.
01g,15aug90,dnw added slot parameter to bootpParamsGet()
+hjb fixed bug in bootpForwarder() not setting hw addr in arp ioctl
01f,12aug90,dnw changed bootpParamsGet() to check every tick for reply message
instead of every 4 seconds, for faster response.
changed bootpParamsGet() to print '.' every time it broadcasts
request.
01e,12aug90,hjb major redesign and implementation of the protocol
01d,07may90,hjb made bootp IP checksum portable; modifications to the protocol
for better forwarding service.
01c,19apr90,hjb minor fixups bootpRequestSend(), added protocol extension
to solve the routing problem when bootp forwarder is used.
01b,11apr90,hjb de-linted.
01a,11mar90,hjb written.
*/
/*
DESCRIPTION
This library implements the client side of the Bootstrap Protocol
(BOOTP). This network protocol allows the dynamic configuration of
the target's boot parameters at boot time. This is in contrast to using the
boot information encoded in system non-volatile RAM or ROM.
Thus, at boot time, BOOTP goes over the network to get an IP address,
a boot file name, and the boot host's IP address.
The actual transfer of the boot image is handled by a file transfer
protocol, such as TFTP or FTP, or by an RSH command.
To access BOOTP services, you can use either the high-level interface
supported by bootpParamsGet(), or the low-level interface supported
by bootpMsgSend().
HIGH-LEVEL INTERFACE
The bootpParamsGet() routine provides the highest level interface to BOOTP.
It accepts a parameter descriptor structure that allows the retrieval of any
combination of the options described in RFC 1533 (if supported by the
BOOTP server and if specified in the database). During system boot, the routine
obtains the boot file, the Internet address, and the host Internet address.
It also obtains the subnet mask and the Internet address of an IP router,
if available.
LOW-LEVEL INTERFACE
The bootpMsgSend() routine provides a lower-level interface to BOOTP. It
accepts and returns a BOOTP message as a parameter. This interface is more
flexible because it gives the caller direct access to the data in the
BOOTP request/reply messages. For example, if the BOOTP message includes
implementation-specific options not defined in an RFC, the caller can
use bootpMsgSend() to retrieve them from the vendor-specific field in
the BOOTP message. The bootpParamsGet() routine already provides
all defined options.
EXAMPLE
The following code provides and example of how to use bootpParamsGet():
.CS
#include "bootpLib.h"
struct bootpParams bootParams;
struct in_addr clntAddr;
struct in_addr hostAddr;
char bootFile [FILENAME_SIZE];
int subnetMask;
struct in_addr_list routerList;
struct in_addr gateway;
char clntAddr [INET_ADDR_LEN];
char bootServer [INET_ADDR_LEN];
char bootFile [SIZE_FILE];
int fileSize;
int subnetMask;
char gateway [INET_ADDR_LEN];
bzero ( (char *)&clntAddr, sizeof (struct in_addr));
bzero ( (char *)&hostAddr, sizeof (struct in_addr));
bzero (bootFile, FILENAME_SIZE);
subnetMask = 0;
bzero ( (char *)&gateway, sizeof (struct in_addr));
/@ Set all pointers in parameter descriptor to NULL. @/
bzero ((char *)&bootParams, sizeof (struct bootpParams));
/@ Set pointers corresponding to desired options. @/
bootParams.clientAddr = &clntAddr;
bootParams.bootHostAddr = &hostAddr;
bootParams.bootfile = pBootFile;
bootParams.netmask = (struct in_addr *)&subnetMask;
routerlist.addr = &gateway;
routerlist.num = 1;
bootParams.routers = &routerlist;
if (bootpParamsGet ("ln0", 0, 0, &bootParams) == ERROR)
return (ERROR);
.CE
NOTE
Certain targets (typically those with no NVRAM) construct their
Ethernet address based on the target's IP address. An IP address
must be entered for these targets in order to boot over the network.
The remaining information can be obtained with BOOTP.
BOOTP is not supported over the following network interfaces: if_sl (SLIP)
and if_ie (Sun IE driver).
if_sl (SLIP) and if_ppp (PPP).
INCLUDE FILES: bootpLib.h
SEE ALSO: bootLib, RFC 951, RFC 1542, RFC 1533,
.pG "Network"
INTERNAL
The BOOTP implementation uses driver input hooks to access the network
interface. The link-level access that mechanism provides is required since
the network is not initially available during boot time because the Internet
address is unknown.
The diagram below defines the structure chart of bootpLib.
(network interface driver)
| |
v v
bootpParamsGet bootpInputHook
/ \ |
| | v
v v
bootpMsgSend bootpParamsFill
*/
/* includes */
#include "vxWorks.h"
#include "bootpLib.h"
#include "netinet/in.h"
#include "netinet/udp.h"
#include "netinet/in_var.h"
#include "netinet/if_ether.h"
#include "etherLib.h"
#include "taskLib.h"
#include "string.h"
#include "stdio.h"
#include "errno.h"
#include "sysLib.h"
#include "tickLib.h"
#include "icmpLib.h"
#include "inetLib.h"
#include "end.h"
#include "muxLib.h"
#include "ipProto.h"
/* defines */
#define ETHER_ADDR_TYPE 1 /* ethernet type */
#define ETHER_ADDR_LEN 6 /* ethernet length */
/* globals */
LOCAL struct
{
struct ip ih; /* IP header */
struct udphdr uh; /* UDP header */
BOOTP_MSG bp; /* Bootp message */
} bootpMsg;
u_long bootpBroadcastAddr = INADDR_BROADCAST; /* bootp broadcast */
int bootpReXmitSecs = INIT_BOOTP_DELAY; /* bootp delay */
/* locals */
LOCAL BOOTP_MSG * pBootpReply; /* pointer to reply */
LOCAL BOOL bootpReplyReceived; /* received reply? */
LOCAL char inputBuffer [ETHERMTU]; /* message buffer */
/* 1048 cookie type */
LOCAL u_char magicCookie1048 [4] = VM_RFC1048;
#define VEOF_RFC1048 {255}
LOCAL u_char endOfVend[1] = VEOF_RFC1048;
/* forward declarations */
LOCAL BOOL bootpInputHook (struct ifnet * pIf, char *einput, int length);
extern in_broadcast ();
/******************************************************************************
*
* bootpParamsGet - retrieve boot parameters using BOOTP
*
* This routine transmits a BOOTP request message over the network interface
* associated with . This interface must already be attached and
* initialized prior to calling this routine.
*
* A non-zero value for specifies an alternate BOOTP server port.
* A zero value means the default BOOTP server port (67).
*
* specifies a timeout value in ticks. If no reply is received
* within this period, an error is returned. Specify zero for an infinite
* value.
*
* is a structure pointer to a `bootpParams' structure that
* you can use to indicate the parameters of interest to you. The `bootpParams'
* structure is defined as follows:
*
* .CS
* struct bootpParams
* {
* struct in_addr * clientAddr;
* struct in_addr * bootHostAddr;
* char * bootfile;
* char * serverName;
*
* struct in_addr * netmask;
* unsigned short * timeOffset;
* struct in_addr_list * routers;
* struct in_addr_list * timeServers;
* struct in_addr_list * nameServers;
* struct in_addr_list * dnsServers;
* struct in_addr_list * logServers;
* struct in_addr_list * cookieServers;
* struct in_addr_list * lprServers;
* struct in_addr_list * impressServers;
* struct in_addr_list * rlpServers;
* char * clientName;
* unsigned short * filesize;
* char * dumpfile;
* char * domainName;
* struct in_addr * swapServer;
* char * rootPath;
* char * extoptPath;
* unsigned char * ipForward;
* unsigned char * nonlocalSourceRoute;
* struct in_addr_list * policyFilter;
* unsigned short * maxDgramSize;
* unsigned char * ipTTL;
* unsigned long * mtuTimeout;
* struct ushort_list * mtuTable;
* unsigned short * intfaceMTU;
* unsigned char * allSubnetsLocal;
* struct in_addr * broadcastAddr;
* unsigned char * maskDiscover;
* unsigned char * maskSupplier;
* unsigned char * routerDiscover;
* struct in_addr * routerDiscAddr;
* struct in_addr_list * staticRoutes;
* unsigned char * arpTrailers;
* unsigned long * arpTimeout;
* unsigned char * etherPacketType;
* unsigned char * tcpTTL;
* unsigned long * tcpInterval;
* unsigned char * tcpGarbage;
* char * nisDomain;
* struct in_addr_list * nisServers;
* struct in_addr_list * ntpServers;
* char * vendString;
* struct in_addr_list * nbnServers;
* struct in_addr_list * nbddServers;
* unsigned char * nbNodeType;
* char * nbScope;
* struct in_addr_list * xFontServers;
* struct in_addr_list * xDisplayManagers;
* char * nispDomain;
* struct in_addr_list * nispServers;
* struct in_addr_list * ipAgents;
* struct in_addr_list * smtpServers;
* struct in_addr_list * pop3Servers;
* struct in_addr_list * nntpServers;
* struct in_addr_list * wwwServers;
* struct in_addr_list * fingerServers;
* struct in_addr_list * ircServers;
* struct in_addr_list * stServers;
* struct in_addr_list * stdaServers;
* };
* .CE
*
* This structure allows the retrieval of any BOOTP option specified in
* RFC 1533. The list of 2-byte (unsigned short) values is defined as:
*
* .CS
* struct ushort_list
* {
* unsigned char num;
* unsigned short * shortlist;
* };
* .CE
*
* The IP address lists use the following similar definition:
*
* .CS
* struct in_addr_list
* {
* unsigned char num;
* struct in_addr * addrlist;
* };
* .CE
*
* When these lists are present, the routine stores values retrieved from
* the BOOTP reply in the location indicated by the `shortlist' or `addrlist'
* members. The amount of space available is indicated by the `num' member.
* When the routine returns, the `num' member indicates the actual number of
* entries retrieved. In the case of `bootpParams.policyFilter.num'
* and `bootpParams.staticRoutes.num', the `num' member value should be
* interpreted as the number of IP address pairs requested and received.
*
* The following members of the `bootpParams' structure are also used for
* both input and output:
*
* .IP `clientAddr'
* Contains a pointer that holds the client's Internet address.
* On input, if it contains a non-NULL value, it is interpreted as a
* pointer to an Internet address of type `struct in_addr' and passed
* on to the BOOTP server in the `bp_ciaddr' member of the BOOTP
* message structure (BOOTP_MSG). The server will use it as a lookup
* field into the BOOTP database. When a reply is received, the client's
* assigned Internet address is copied to the `clientAddr' member.
*
* .IP `bootHostAddr'
* Contains a pointer that holds the host's IP address. On input,
* if it contains a non-NULL value, it is interpreted as the host where
* the BOOTP message is to be sent. Note that this host must be local
* to the network. If NULL, the BOOTP message is sent to the local
* broadcast address. On return, the host's IP address is copied to
* the `bootHostAddr' member.
*
* On input, if the `bootpParams.bootfile' member points to a non-empty
* string, the contents are passed to the BOOTP server in the `bp_file'
* member of the BOOTP message structure (BOOTP_MSG). When a reply is
* received, the file name retrieved from the BOOTP server is copied to
* the `bootpParams.bootfile' member as a NULL-terminated string.
*
* .LP
* The remaining elements in the BOOTP parameters descriptor are used to select
* options for retrieval from the BOOTP server. The BOOTP library attempts to
* retrieve the values for any options whose corresponding field pointers are
* non-NULL values. To obtain these parameters, the BOOTP server must support
* the vendor-specific options described in RFC 1048 (or its successors) and the
* corresponding parameters must be specified in the BOOTP server database.
* Where meaningful, the values are returned in host byte order.
*
* The BOOTP request issued during system startup attempts to retrieve a subnet
* mask for the boot device, in addition to the host and client addresses,
* and the boot file name.
*
* RETURNS: OK, or ERROR if unsuccessful.
*
* SEE ALSO: bootLib, RFC 1048, RFC 1533
*/
STATUS bootpParamsGet
(
char * ifName, /* network interface name */
int port, /* optional port number */
u_int timeOut, /* timeout in ticks */
struct bootpParams * pBootpParams /* parameters descriptor */
)
{
BOOTP_MSG bootpMessage; /* bootp message */
struct in_addr ipDest; /* ip dest address */
int length;
/* fill in bootp message */
bzero ((char *) &bootpMessage, sizeof (BOOTP_MSG));
/* Check for client IP address. */
if (pBootpParams->clientAddr != NULL)
bootpMessage.bp_ciaddr = *pBootpParams->clientAddr;
/* Check for host address, or use broadcast address. */
if (pBootpParams->bootHostAddr == NULL ||
pBootpParams->bootHostAddr->s_addr == 0)
ipDest.s_addr = htonl (bootpBroadcastAddr);
else
ipDest = *pBootpParams->bootHostAddr;
/* Check for partial boot file. */
if (pBootpParams->bootfile != NULL)
{
length = strlen (pBootpParams->bootfile);
if (length > SIZE_FILE)
length = SIZE_FILE;
(void) strncpy ( (char *) bootpMessage.bp_file, pBootpParams->bootfile,
length);
}
/* Fill in RFC1048 magic cookie if vendor-specific info requested. */
if (bootpOptionCheck (pBootpParams))
{
bcopy ( (char *) magicCookie1048, (char *) bootpMessage.bp_vend,
sizeof (magicCookie1048));
bcopy ( (char *) endOfVend, (char *) bootpMessage.bp_vend +
sizeof(magicCookie1048), sizeof(endOfVend));
}
/* send bootp message */
if (bootpMsgSend (ifName, &ipDest, port, &bootpMessage, timeOut) == ERROR)
return (ERROR);
/* Fill in any options requested by user and provided by server. */
bootpParamsFill (pBootpParams);
return (OK);
}
/******************************************************************************
*
* bootpOptionCheck - check if user wants optional parameters
*
* This routine is called to determine whether the magic cookie specified
* in RFC 1048 should be inserted into the vendor specifications field of
* a BOOTP request. The cookie is inserted if the user has set any pointer
* in the parameter descriptor which correspond to BOOTP options to a
* non-NULL value.
*
* RETURNS: TRUE if options requested, or FALSE otherwise.
*
* ERRNO: N/A
*
* NOMANUAL
*/
BOOL bootpOptionCheck
(
struct bootpParams * pBootpParams /* parameters descriptor */
)
{
BOOL result;
result = FALSE;
if (pBootpParams->netmask != NULL)
result = TRUE;
else if (pBootpParams->timeOffset != NULL)
result = TRUE;
else if (pBootpParams->routers != NULL)
result = TRUE;
else if (pBootpParams->timeServers != NULL)
result = TRUE;
else if (pBootpParams->nameServers != NULL)
result = TRUE;
else if (pBootpParams->dnsServers != NULL)
result = TRUE;
else if (pBootpParams->logServers != NULL)
result = TRUE;
else if (pBootpParams->cookieServers != NULL)
result = TRUE;
else if (pBootpParams->lprServers != NULL)
result = TRUE;
else if (pBootpParams->impressServers != NULL)
result = TRUE;
else if (pBootpParams->rlpServers != NULL)
result = TRUE;
else if (pBootpParams->clientName != NULL)
result = TRUE;
else if (pBootpParams->filesize != NULL)
result = TRUE;
else if (pBootpParams->dumpfile != NULL)
result = TRUE;
else if (pBootpParams->domainName != NULL)
result = TRUE;
else if (pBootpParams->swapServer != NULL)
result = TRUE;
else if (pBootpParams->rootPath != NULL)
result = TRUE;
else if (pBootpParams->extoptPath != NULL)
result = TRUE;
else if (pBootpParams->ipForward != NULL)
result = TRUE;
else if (pBootpParams->nonlocalSourceRoute != NULL)
result = TRUE;
else if (pBootpParams->policyFilter != NULL)
result = TRUE;
else if (pBootpParams->maxDgramSize != NULL)
result = TRUE;
else if (pBootpParams->ipTTL != NULL)
result = TRUE;
else if (pBootpParams->mtuTimeout != NULL)
result = TRUE;
else if (pBootpParams->mtuTable != NULL)
result = TRUE;
else if (pBootpParams->intfaceMTU != NULL)
result = TRUE;
else if (pBootpParams->allSubnetsLocal != NULL)
result = TRUE;
else if (pBootpParams->broadcastAddr != NULL)
result = TRUE;
else if (pBootpParams->maskDiscover != NULL)
result = TRUE;
else if (pBootpParams->maskSupplier != NULL)
result = TRUE;
else if (pBootpParams->routerDiscover != NULL)
result = TRUE;
else if (pBootpParams->routerDiscAddr != NULL)
result = TRUE;
else if (pBootpParams->staticRoutes != NULL)
result = TRUE;
else if (pBootpParams->arpTrailers != NULL)
result = TRUE;
else if (pBootpParams->arpTimeout != NULL)
result = TRUE;
else if (pBootpParams->etherPacketType != NULL)
result = TRUE;
else if (pBootpParams->tcpTTL != NULL)
result = TRUE;
else if (pBootpParams->tcpInterval != NULL)
result = TRUE;
else if (pBootpParams->tcpGarbage != NULL)
result = TRUE;
else if (pBootpParams->nisDomain != NULL)
result = TRUE;
else if (pBootpParams->nisServers != NULL)
result = TRUE;
else if (pBootpParams->ntpServers != NULL)
result = TRUE;
else if (pBootpParams->vendString != NULL)
result = TRUE;
else if (pBootpParams->nbnServers != NULL)
result = TRUE;
else if (pBootpParams->nbddServers != NULL)
result = TRUE;
else if (pBootpParams->nbNodeType != NULL)
result = TRUE;
else if (pBootpParams->nbScope != NULL)
result = TRUE;
else if (pBootpParams->xFontServers != NULL)
result = TRUE;
else if (pBootpParams->xDisplayManagers != NULL)
result = TRUE;
else if (pBootpParams->nispDomain != NULL)
result = TRUE;
else if (pBootpParams->nispServers != NULL)
result = TRUE;
else if (pBootpParams->ipAgents != NULL)
result = TRUE;
else if (pBootpParams->smtpServers != NULL)
result = TRUE;
else if (pBootpParams->pop3Servers != NULL)
result = TRUE;
else if (pBootpParams->nntpServers != NULL)
result = TRUE;
else if (pBootpParams->wwwServers != NULL)
result = TRUE;
else if (pBootpParams->fingerServers != NULL)
result = TRUE;
else if (pBootpParams->ircServers != NULL)
result = TRUE;
else if (pBootpParams->stServers != NULL)
result = TRUE;
else if (pBootpParams->stdaServers != NULL)
result = TRUE;
return (result);
}
/******************************************************************************
*
* bootpParamsFill - copy requested BOOTP options
*
* This routine fills in the non-NULL fields in the given parameter descriptor
* with the corresponding entries from the received BOOTP message. It is only
* called internally after bootpMsgSend() completes successfully.
*
* RETURNS: N/A
*
* ERRNO: N/A
*
* NOMANUAL
*/
void bootpParamsFill
(
struct bootpParams * pBootpParams /* parameters descriptor */
)
{
int loop;
int limit;
u_char * cp;
int length;
int number;
/* Copy entries from message body if requested by user. */
/* Fill in assigned IP address. */
if (pBootpParams->clientAddr != NULL)
*pBootpParams->clientAddr = pBootpReply->bp_yiaddr;
/* Fill in host IP address. */
if (pBootpParams->bootHostAddr != NULL)
*pBootpParams->bootHostAddr = pBootpReply->bp_siaddr;
/* Fill in boot file. */
if (pBootpParams->bootfile != NULL)
{
if (pBootpReply->bp_file [0] == EOS)
{
printf ("\nno boot file specified. Check file permissions");
printf (" (must be world readable).\n");
pBootpParams->bootfile[0] = EOS;
}
else
(void)strcpy (pBootpParams->bootfile,
(char *)pBootpReply->bp_file);
}
/* Fill in server name. */
if (pBootpParams->serverName != NULL)
if (pBootpReply->bp_sname[0] == EOS)
pBootpParams->serverName[0] = EOS;
else
strcpy(pBootpParams->serverName, pBootpReply->bp_sname);
/* Fill in optional entries requested by user, if present in reply. */
/* Retrieve subnet mask. */
if (pBootpParams->netmask != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_SUBNET_MASK, &length);
if (cp != NULL)
bcopy ( (char *) cp, (char *)pBootpParams->netmask, length);
else
bzero ( (char *)pBootpParams->netmask, sizeof (struct in_addr));
}
/* Retrieve time offset. */
if (pBootpParams->timeOffset != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_TIME_OFFSET, &length);
if (cp != NULL)
*pBootpParams->timeOffset = ntohs (*(unsigned short *)cp);
else
*pBootpParams->timeOffset = 0;
}
/* Retrieve IP addresses of IP routers, up to number requested. */
if (pBootpParams->routers != NULL &&
pBootpParams->routers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_GATEWAY, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->routers->num < number) ?
pBootpParams->routers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->routers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->routers->num = limit;
}
/* Retrieve IP addresses of time servers, up to number requested. */
if (pBootpParams->timeServers != NULL &&
pBootpParams->timeServers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_TIME_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->timeServers->num < number) ?
pBootpParams->timeServers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->timeServers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->timeServers->num = limit;
}
/* Retrieve IP addresses of name servers, up to number requested. */
if (pBootpParams->nameServers != NULL &&
pBootpParams->nameServers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_NAME_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->nameServers->num < number) ?
pBootpParams->nameServers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->nameServers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->nameServers->num = limit;
}
/* Retrieve IP addresses of DNS servers, up to number requested. */
if (pBootpParams->dnsServers != NULL &&
pBootpParams->dnsServers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_DNS_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->dnsServers->num < number) ?
pBootpParams->dnsServers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->dnsServers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->dnsServers->num = limit;
}
/* Retrieve IP addresses of log servers, up to number requested. */
if (pBootpParams->logServers != NULL &&
pBootpParams->logServers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_LOG_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->logServers->num < number) ?
pBootpParams->logServers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->logServers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->logServers->num = limit;
}
/* Retrieve IP addresses of cookie servers, up to number requested. */
if (pBootpParams->cookieServers != NULL &&
pBootpParams->cookieServers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_COOKIE_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->cookieServers->num < number) ?
pBootpParams->cookieServers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->cookieServers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->cookieServers->num = limit;
}
/* Retrieve IP addresses of LPR servers, up to number requested. */
if (pBootpParams->lprServers != NULL &&
pBootpParams->lprServers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_LPR_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->lprServers->num < number) ?
pBootpParams->lprServers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->lprServers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->lprServers->num = limit;
}
/* Retrieve IP addresses of Impress servers, up to number requested. */
if (pBootpParams->impressServers != NULL &&
pBootpParams->impressServers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_IMPRESS_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->impressServers->num < number) ?
pBootpParams->impressServers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->impressServers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->impressServers->num = limit;
}
/* Retrieve IP addresses of RLP servers, up to number requested. */
if (pBootpParams->rlpServers != NULL &&
pBootpParams->rlpServers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_RLP_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->rlpServers->num < number) ?
pBootpParams->rlpServers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->rlpServers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->rlpServers->num = limit;
}
/* Retrieve hostname of client. */
if (pBootpParams->clientName != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_HOSTNAME, &length);
if (cp != NULL)
{
bcopy ( (char *)cp, pBootpParams->clientName, length);
pBootpParams->clientName [length] = EOS;
}
else
pBootpParams->clientName[0] = EOS;
}
/* Retrieve size of boot file. */
if (pBootpParams->filesize != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_BOOTSIZE, &length);
if (cp != NULL)
*pBootpParams->filesize = ntohs (*(unsigned short *)cp);
else
*pBootpParams->filesize = 0;
}
/* Retrieve name of dump file. */
if (pBootpParams->dumpfile != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_MERIT_DUMP, &length);
if (cp != NULL)
{
bcopy ( (char *)cp, pBootpParams->dumpfile, length);
pBootpParams->dumpfile [length] = EOS;
}
else
pBootpParams->dumpfile[0] = EOS;
}
/* Retrieve name of DNS domain. */
if (pBootpParams->domainName != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_DNS_DOMAIN, &length);
if (cp != NULL)
{
bcopy ( (char *)cp, pBootpParams->domainName, length);
pBootpParams->domainName [length] = EOS;
}
else
pBootpParams->domainName[0] = EOS;
}
/* Retrieve IP address of swap server. */
if (pBootpParams->swapServer != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_SWAP_SERVER, &length);
if (cp != NULL)
bcopy ( (char *)cp, (char *)pBootpParams->swapServer, length);
else
bzero ( (char *)pBootpParams->swapServer, sizeof (struct in_addr));
}
/* Retrieve pathname of root disk. */
if (pBootpParams->rootPath != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_ROOT_PATH, &length);
if (cp != NULL)
{
bcopy ( (char *)cp, pBootpParams->rootPath, length);
pBootpParams->rootPath [length] = EOS;
}
else
pBootpParams->rootPath[0] = EOS;
}
/* Retrieve pathname of extended options file. */
if (pBootpParams->extoptPath != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_EXTENSIONS_PATH, &length);
if (cp != NULL)
{
bcopy ( (char *)cp, pBootpParams->extoptPath, length);
pBootpParams->extoptPath [length] = EOS;
}
else
pBootpParams->extoptPath[0] = EOS;
}
/* Retrieve IP forwarding option. */
if (pBootpParams->ipForward != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_IP_FORWARD, &length);
if (cp != NULL)
*pBootpParams->ipForward = *cp;
else
*pBootpParams->ipForward = 0;
}
/* Retrieve non-local source routing option. */
if (pBootpParams->nonlocalSourceRoute != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_NONLOCAL_SRCROUTE,
&length);
if (cp != NULL)
*pBootpParams->nonlocalSourceRoute = *cp;
else
*pBootpParams->nonlocalSourceRoute = 0;
}
/* Retrieve IP addresses and masks for policy filter option. */
if (pBootpParams->policyFilter != NULL &&
pBootpParams->policyFilter->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_POLICY_FILTER, &length);
if (cp != NULL)
{
/* Find number of pairs to retrieve. */
number = length / (2 * sizeof (struct in_addr));
limit = (pBootpParams->policyFilter->num < number) ?
pBootpParams->policyFilter->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->policyFilter->addrlist[2 * loop],
2 * sizeof (struct in_addr));
cp += 2 * sizeof (struct in_addr);
}
}
pBootpParams->policyFilter->num = limit;
}
/* Retrieve size of maximum IP datagram. */
if (pBootpParams->maxDgramSize != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_MAX_DGRAM_SIZE, &length);
if (cp != NULL)
*pBootpParams->maxDgramSize = ntohs (*(unsigned short *)cp);
else
*pBootpParams->maxDgramSize = 0;
}
/* Retrieve default IP time-to-live value. */
if (pBootpParams->ipTTL != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_DEFAULT_IP_TTL, &length);
if (cp != NULL)
*pBootpParams->ipTTL = *cp;
else
*pBootpParams->ipTTL = 0;
}
/* Retrieve value for path MTU aging timeout. */
if (pBootpParams->mtuTimeout != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_MTU_AGING_TIMEOUT,
&length);
if (cp != NULL)
*pBootpParams->mtuTimeout = ntohs (*(unsigned long *)cp);
else
*pBootpParams->mtuTimeout = 0;
}
/* Retrieve table of MTU sizes. */
if (pBootpParams->mtuTable != NULL &&
pBootpParams->mtuTable->shortlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_MTU_PLATEAU_TABLE,
&length);
if (cp != NULL)
{
number = length / sizeof (unsigned short);
limit = (pBootpParams->mtuTable->num < number) ?
pBootpParams->mtuTable->num : number;
for (loop = 0; loop < limit; loop++)
{
pBootpParams->mtuTable->shortlist [loop] =
ntohs (*(unsigned short *)cp);
cp += sizeof (unsigned short);
}
}
pBootpParams->mtuTable->num = limit;
}
/* Retrieve interface MTU. */
if (pBootpParams->intfaceMTU != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_IF_MTU, &length);
if (cp != NULL)
*pBootpParams->intfaceMTU = ntohs (*(unsigned short *)cp);
else
*pBootpParams->intfaceMTU = 0;
}
/* Retrieve all subnets local option. */
if (pBootpParams->allSubnetsLocal != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_ALL_SUBNET_LOCAL,
&length);
if (cp != NULL)
*pBootpParams->allSubnetsLocal = *cp;
else
*pBootpParams->allSubnetsLocal = 0;
}
/* Retrieve broadcast IP address. */
if (pBootpParams->broadcastAddr != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_BRDCAST_ADDR, &length);
if (cp != NULL)
bcopy ( (char *) cp, (char *)pBootpParams->broadcastAddr, length);
else
bzero ( (char *)pBootpParams->broadcastAddr,
sizeof (struct in_addr));
}
/* Retrieve mask discovery option. */
if (pBootpParams->maskDiscover != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_MASK_DISCOVER, &length);
if (cp != NULL)
*pBootpParams->maskDiscover = *cp;
else
*pBootpParams->maskDiscover = 0;
}
/* Retrieve mask supplier option. */
if (pBootpParams->maskSupplier != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_MASK_SUPPLIER, &length);
if (cp != NULL)
*pBootpParams->maskSupplier = *cp;
else
*pBootpParams->maskSupplier = 0;
}
/* Retrieve router discovery option. */
if (pBootpParams->routerDiscover != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_ROUTER_DISCOVER, &length);
if (cp != NULL)
*pBootpParams->routerDiscover = *cp;
else
*pBootpParams->routerDiscover = 0;
}
/* Retrieve IP address for router solicitation. */
if (pBootpParams->routerDiscAddr != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_ROUTER_SOLICIT, &length);
if (cp != NULL)
bcopy ( (char *) cp, (char *)pBootpParams->routerDiscAddr, length);
else
bzero ( (char *)pBootpParams->routerDiscAddr,
sizeof (struct in_addr));
}
/* Retrieve static routing table. */
if (pBootpParams->staticRoutes != NULL &&
pBootpParams->staticRoutes->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_STATIC_ROUTE, &length);
if (cp != NULL)
{
/* Find number of pairs to retrieve. */
number = length / (2 * sizeof (struct in_addr));
limit = (pBootpParams->staticRoutes->num < number) ?
pBootpParams->staticRoutes->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->staticRoutes->addrlist[2 * loop],
2 * sizeof (struct in_addr));
cp += 2 * sizeof (struct in_addr);
}
}
pBootpParams->staticRoutes->num = limit;
}
/* Retrieve ARP trailer encapsulation option. */
if (pBootpParams->arpTrailers != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_TRAILER, &length);
if (cp != NULL)
*pBootpParams->arpTrailers = *cp;
else
*pBootpParams->arpTrailers = 0;
}
/* Retrieve value for ARP cache timeout. */
if (pBootpParams->arpTimeout != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_ARP_CACHE_TIMEOUT,
&length);
if (cp != NULL)
*pBootpParams->arpTimeout = ntohs (*(unsigned long *)cp);
else
*pBootpParams->arpTimeout = 0;
}
/* Retrieve Ethernet encapsulation option. */
if (pBootpParams->etherPacketType != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_ETHER_ENCAP, &length);
if (cp != NULL)
*pBootpParams->etherPacketType = *cp;
else
*pBootpParams->etherPacketType = 0;
}
/* Retrieve default TCP time-to-live value. */
if (pBootpParams->tcpTTL != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_DEFAULT_TCP_TTL, &length);
if (cp != NULL)
*pBootpParams->tcpTTL = *cp;
else
*pBootpParams->tcpTTL = 0;
}
/* Retrieve value for TCP keepalive interval. */
if (pBootpParams->tcpInterval != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_KEEPALIVE_INTER, &length);
if (cp != NULL)
*pBootpParams->tcpInterval = ntohs (*(unsigned long *)cp);
else
*pBootpParams->tcpInterval = 0;
}
/* Retrieve value for TCP keepalive garbage option. */
if (pBootpParams->tcpGarbage != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_KEEPALIVE_GARBA, &length);
if (cp != NULL)
*pBootpParams->tcpGarbage = *cp;
else
*pBootpParams->tcpGarbage = 0;
}
/* Retrieve NIS domain name. */
if (pBootpParams->nisDomain != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_NIS_DOMAIN, &length);
if (cp != NULL)
{
bcopy ( (char *)cp, pBootpParams->nisDomain, length);
pBootpParams->nisDomain [length] = EOS;
}
else
pBootpParams->nisDomain[0] = EOS;
}
/* Retrieve IP addresses of NIS servers, up to number requested. */
if (pBootpParams->nisServers != NULL &&
pBootpParams->nisServers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_NIS_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->nisServers->num < number) ?
pBootpParams->nisServers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->nisServers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->nisServers->num = limit;
}
/* Retrieve IP addresses of NTP servers, up to number requested. */
if (pBootpParams->ntpServers != NULL &&
pBootpParams->ntpServers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_NTP_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->ntpServers->num < number) ?
pBootpParams->ntpServers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->ntpServers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->ntpServers->num = limit;
}
/* Retrieve vendor specific information. */
if (pBootpParams->vendString != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_VENDOR_SPEC, &length);
if (cp != NULL)
{
bcopy ( (char *)cp, pBootpParams->vendString, length);
pBootpParams->vendString [length] = EOS;
}
else
pBootpParams->vendString[0] = EOS;
}
/* Retrieve IP addresses of NetBIOS name servers. */
if (pBootpParams->nbnServers != NULL &&
pBootpParams->nbnServers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_NBN_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->nbnServers->num < number) ?
pBootpParams->nbnServers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->nbnServers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->nbnServers->num = limit;
}
/* Retrieve IP addresses of NetBIOS datagram distribution servers. */
if (pBootpParams->nbddServers != NULL &&
pBootpParams->nbddServers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_NBDD_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->nbddServers->num < number) ?
pBootpParams->nbddServers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->nbddServers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->nbddServers->num = limit;
}
/* Retrieve value for NetBIOS Node Type option. */
if (pBootpParams->nbNodeType != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_NB_NODETYPE, &length);
if (cp != NULL)
*pBootpParams->nbNodeType = *cp;
else
*pBootpParams->nbNodeType = 0;
}
/* Retrieve NetBIOS scope. */
if (pBootpParams->nbScope != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_NB_SCOPE, &length);
if (cp != NULL)
{
bcopy ( (char *)cp, pBootpParams->nbScope, length);
pBootpParams->nbScope [length] = EOS;
}
else
pBootpParams->nbScope[0] = EOS;
}
/* Retrieve IP addresses of X Window font servers. */
if (pBootpParams->xFontServers != NULL &&
pBootpParams->xFontServers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_XFONT_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->xFontServers->num < number) ?
pBootpParams->xFontServers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->xFontServers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->xFontServers->num = limit;
}
/* Retrieve IP addresses of X Window Display Manager systems. */
if (pBootpParams->xDisplayManagers != NULL &&
pBootpParams->xDisplayManagers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_XDISPLAY_MANAGER,
&length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->xDisplayManagers->num < number) ?
pBootpParams->xDisplayManagers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->xDisplayManagers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->xDisplayManagers->num = limit;
}
/* Retrieve NIS+ domain name. */
if (pBootpParams->nispDomain != NULL)
{
length = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_NISP_DOMAIN, &length);
if (cp != NULL)
{
bcopy ( (char *)cp, pBootpParams->nispDomain, length);
pBootpParams->nispDomain [length] = EOS;
}
else
pBootpParams->nispDomain[0] = EOS;
}
/* Retrieve IP addresses of NIS+ servers. */
if (pBootpParams->nispServers != NULL &&
pBootpParams->nispServers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_NISP_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->nispServers->num < number) ?
pBootpParams->nispServers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->nispServers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->nispServers->num = limit;
}
/* Retrieve IP addresses of Mobile IP Home Agents. */
if (pBootpParams->ipAgents != NULL &&
pBootpParams->ipAgents->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_MOBILEIP_HA, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->ipAgents->num < number) ?
pBootpParams->ipAgents->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->ipAgents->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->ipAgents->num = limit;
}
/* Retrieve IP addresses of SMTP servers. */
if (pBootpParams->smtpServers != NULL &&
pBootpParams->smtpServers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_SMTP_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->smtpServers->num < number) ?
pBootpParams->smtpServers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->smtpServers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->smtpServers->num = limit;
}
/* Retrieve IP addresses of POP3 servers. */
if (pBootpParams->pop3Servers != NULL &&
pBootpParams->pop3Servers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_POP3_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->pop3Servers->num < number) ?
pBootpParams->pop3Servers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->pop3Servers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->pop3Servers->num = limit;
}
/* Retrieve IP addresses of NNTP servers. */
if (pBootpParams->nntpServers != NULL &&
pBootpParams->nntpServers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_NNTP_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->nntpServers->num < number) ?
pBootpParams->nntpServers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->nntpServers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->nntpServers->num = limit;
}
/* Retrieve IP addresses of World Wide Web servers. */
if (pBootpParams->wwwServers != NULL &&
pBootpParams->wwwServers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_WWW_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->wwwServers->num < number) ?
pBootpParams->wwwServers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->wwwServers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->wwwServers->num = limit;
}
/* Retrieve IP addresses of finger servers. */
if (pBootpParams->fingerServers != NULL &&
pBootpParams->fingerServers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_FINGER_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->fingerServers->num < number) ?
pBootpParams->fingerServers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->fingerServers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->fingerServers->num = limit;
}
/* Retrieve IP addresses of Internet Relay Chat servers. */
if (pBootpParams->ircServers != NULL &&
pBootpParams->ircServers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_IRC_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->ircServers->num < number) ?
pBootpParams->ircServers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->ircServers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->ircServers->num = limit;
}
/* Retrieve IP addresses of StreetTalk servers. */
if (pBootpParams->stServers != NULL &&
pBootpParams->stServers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_ST_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->stServers->num < number) ?
pBootpParams->stServers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->stServers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->stServers->num = limit;
}
/* Retrieve IP addresses of STDA servers. */
if (pBootpParams->stdaServers != NULL &&
pBootpParams->stdaServers->addrlist != NULL)
{
length = 0;
limit = 0;
cp = bootpTagFind (pBootpReply->bp_vend, TAG_STDA_SERVER, &length);
if (cp != NULL)
{
number = length / sizeof (struct in_addr);
limit = (pBootpParams->stdaServers->num < number) ?
pBootpParams->stdaServers->num : number;
for (loop = 0; loop < limit; loop++)
{
bcopy ( (char *)cp,
(char *)&pBootpParams->stdaServers->addrlist[loop],
sizeof (struct in_addr));
cp += sizeof (struct in_addr);
}
}
pBootpParams->stdaServers->num = limit;
}
return;
}
/******************************************************************************
*
* bootpMsgSend - send a BOOTP request message
*
* This routine sends the BOOTP message indicated by using the
* network interface specified by . The argument specifies
* the destination IP address. In most cases, the broadcast address
* (255.255.255.255) is used. However, this parameter also accepts the IP
* address of a particular BOOTP server. That server must reside on the
* same subnet as the specified network interface.
*
* A non-zero value for specifies an alternate BOOTP server port.
* Otherwise, the default port (67) is used.
*
* This routine always sets the values of the `bp_op', `bp_xid', and `bp_secs'
* members in the BOOTP message structure, but it allows the caller to assign
* values to any of the other members. However, if the `bp_hlen' member is 0,
* the routine uses the Ethernet address of the specified network interface
* for the `bp_chaddr' member and sets `bp_type' to 1 and `bp_hlen' to 6 as
* required for that address.
*
* The bootpMsgSend() routine will retransmit the BOOTP message if it gets no
* reply. The retransmission time increases exponentially but is bounded
* by the number of ticks specified in the parameter. If no reply is
* received within this period, an error is returned. A value of zero specifies
* an infinite timeout value.
*
* NOTE: If `bp_ciaddr' is specified, the BOOTP server may assume that the
* client will respond to an ARP request.
*
* RETURNS: OK, or ERROR.
*
* ERRNO
* S_bootpLib_INVALID_ARGUMENT
* S_bootpLib_NO_BROADCASTS
* S_bootpLib_TIME_OUT
*/
STATUS bootpMsgSend
(
char * ifName, /* network interface name */
struct in_addr * pIpDest, /* destination IP address */
int port, /* port number */
BOOTP_MSG * pBootpMsg, /* pointer to BOOTP message */
u_int timeOut /* timeout in ticks */
)
{
FAST int tickCount; /* tick counter */
FAST int tickStart; /* start of transmissions */
FAST int retransmitSecs; /* retransmission time */
int backOffTicks; /* semi random backoff time */
struct in_addr ipSrc; /* source */
struct ifnet * pIf; /* pointer to interface */
BOOL firstXmit = TRUE;/* first transmission */
END_OBJ * pEnd;
if ((pBootpMsg == NULL) || ((pIf = ifunit (ifName)) == NULL))
/* validate args */
{
errno = S_bootpLib_INVALID_ARGUMENT;
return (ERROR);
}
pEnd = endFindByName (pIf->if_name, pIf->if_unit);
/* if destination is a broadcast, then be sure the interface allows it */
if ( (in_broadcast (*pIpDest, pIf)) &&
( (pIf->if_flags & IFF_BROADCAST) == 0))
{
errno = S_bootpLib_NO_BROADCASTS;
return (ERROR);
}
pIf->if_flags |= (IFF_UP | IFF_RUNNING);
/* initialize values */
bootpReplyReceived = FALSE;
tickStart = tickGet ();
retransmitSecs = bootpReXmitSecs;
/* if source is a broadcast then set address to zero */
ipSrc.s_addr = in_broadcast (pBootpMsg->bp_ciaddr, pIf) ?
htons ((u_short) 0) : pBootpMsg->bp_ciaddr.s_addr;
/*
* generate a (semi) random backoff time between 1 & 5 seconds, then
* convert it to ticks.
*/
backOffTicks = ( ( ( (struct arpcom *)pIf)->ac_enaddr [5] +
( (struct arpcom *)pIf)->ac_enaddr [4] +
( (struct arpcom *)pIf)->ac_enaddr [3]) % 5) *
sysClkRateGet ();
bzero ( (char *)&bootpMsg, sizeof (bootpMsg));
/* fill in BOOTP message */
bootpMsg.bp = *pBootpMsg;
bootpMsg.bp.bp_op = BOOTREQUEST; /* operation */
bootpMsg.bp.bp_xid = tickGet (); /* transmission id */
/* If hardware len is 0, then use Ethernet address as hardware address. */
if (bootpMsg.bp.bp_hlen == 0)
{
bootpMsg.bp.bp_htype = ETHER_ADDR_TYPE;
bootpMsg.bp.bp_hlen = ETHER_ADDR_LEN;
bcopy ( (char *) ( (struct arpcom *)pIf)->ac_enaddr,
(char *)bootpMsg.bp.bp_chaddr, ETHER_ADDR_LEN);
}
/* fill in the UDP header */
bootpMsg.uh.uh_sport = htons ((u_short) IPPORT_BOOTPC);
bootpMsg.uh.uh_dport = (port == 0) ? htons ((u_short) IPPORT_BOOTPS) :
htons ((u_short) port);
bootpMsg.uh.uh_ulen = htons (sizeof (bootpMsg.uh) + sizeof (bootpMsg.bp));
bootpMsg.uh.uh_sum = 0;
ipHeaderCreate (IPPROTO_UDP, &ipSrc, pIpDest, &bootpMsg.ih,
sizeof (bootpMsg));
/* get ready for incoming packets */
if (pEnd)
{
if (etherInputHookAdd (bootpInputHook, pIf->if_name, pIf->if_unit)
== ERROR)
return (ERROR);
}
else
{
if (etherInputHookAdd (bootpInputHook, NULL, 0) == ERROR)
return (ERROR);
}
FOREVER
{
if (etherSend (pIf, &bootpMsg.ih, sizeof (bootpMsg)) == ERROR)
{
if (pEnd)
etherInputHookDelete (bootpInputHook, pIf->if_name,
pIf->if_unit);
else
etherInputHookDelete (bootpInputHook);
return (ERROR);
}
/* calculate rexmit time */
tickCount = retransmitSecs * sysClkRateGet ();
if (firstXmit) /* add backoff */
{
tickCount += backOffTicks;
firstXmit = FALSE;
}
/* wait for a reply */
do
{
if (bootpReplyReceived) /* got reply !! */
{
if (pEnd)
etherInputHookDelete (bootpInputHook, pIf->if_name,
pIf->if_unit);
else
etherInputHookDelete (bootpInputHook);
bcopy ( (char *)pBootpReply, (char *)pBootpMsg,
sizeof (BOOTP_MSG));
return (OK);
}
taskDelay (1);
if ( (timeOut != 0) && (--timeOut == 0))
{ /* user timer expired - bail */
errno = S_bootpLib_TIME_OUT;
if (pEnd)
etherInputHookDelete (bootpInputHook, pIf->if_name,
pIf->if_unit);
else
etherInputHookDelete (bootpInputHook);
return (ERROR);
}
}
while (tickCount-- > 0);
retransmitSecs = min (retransmitSecs << 1, MAX_BOOTP_DELAY);
bootpMsg.bp.bp_secs = htons ( (u_short) ( (tickGet () - tickStart) /
sysClkRateGet ()));
}
}
/*******************************************************************************
*
* bootpInputHook - input hook to filter out the BOOTP reply message
*
* This routine filters out the BOOTP reply message from incoming Ethernet
* traffic. This function is called by the network interface driver when
* a new input frame comes in from the network. It is "hooked" into the
* driver via `etherHook' routines.
*
* RETURNS:
* TRUE indicating the Ethernet frame is handled by this routine and
* no further processing need be done by the network interface driver.
* FALSE indicating the ethernet frame is to be handled by the network
* interface driver.
*
* NOMANUAL
*/
LOCAL BOOL bootpInputHook
(
struct ifnet * pIf, /* network interface pointer */
FAST char * einput, /* input data frame pointer */
FAST int length /* input data length */
)
{
FAST struct ether_header * eh; /* pointer to ethernet header */
FAST struct udphdr * udph; /* pointer to udp header */
int bufLen; /* buffer length */
if (bootpReplyReceived) /* ignore it - we got a reply */
return (FALSE);
eh = (struct ether_header *) einput;
if ( (length <= SIZEOF_ETHERHEADER) ||
(ntohs (eh->ether_type) != ETHERTYPE_IP))
return (FALSE);
/*
* copy the input packet in the most conservative way
* to accommodate board specific memory access requirements.
*/
bufLen = length - SIZEOF_ETHERHEADER;
bcopyBytes ( (char *) ( (u_char *)einput + SIZEOF_ETHERHEADER),
inputBuffer, bufLen);
udph = (struct udphdr *)ipHeaderVerify ( (struct ip *)inputBuffer, bufLen,
IPPROTO_UDP);
if (udph == NULL)
return (FALSE);
if (ntohs (udph->uh_dport) != IPPORT_BOOTPC)
return (FALSE);
pBootpReply = (BOOTP_MSG *) ( (u_char *)udph + sizeof (struct udphdr));
/* must be a boot reply, addressed to me, with the right id. */
if ( (pBootpReply->bp_op != BOOTREPLY) ||
(bcmp ( (char *)pBootpReply->bp_chaddr,
(char *) bootpMsg.bp.bp_chaddr, ETHER_ADDR_LEN) != 0) ||
(pBootpReply->bp_xid != bootpMsg.bp.bp_xid))
return (FALSE);
bootpReplyReceived = TRUE;
return (TRUE);
}
/*******************************************************************************
*
* bootpTagFind - find data for a BOOTP options tag
*
* This routine finds the data associated with tag in the
* vendor-specific member of a BOOTP message. The parameter must
* be a valid 1533 vendor-tag value. Only values that have data
* associated with them are considered valid (for example, TAG_END
* and TAG_PAD are not valid values because they have no data).
* The parameter is a pointer to the beginning of the
* vendor-specific member in the BOOTP message. If is found
* in , the length of the associated data gets placed in
* and a pointer to the data is returned.
*
* INTERNAL
* The vendor information field is divided into extendable tagged subfields.
* Tags that have no data, consist of a single tag octet and are one octet
* in length. All other tags have a one tag octet, a length octet and length
* octets of data. For a more complete description of the tags and how they
* are parsed, please refer to RFC 1048 or its successors. All tags defined
* through RFC 1533 are supported.
*
* RETURNS: A pointer to tag data if successful, otherwise NULL.
*
* ERRNO
* S_bootpLib_INVALID_ARGUMENT
* S_bootpLib_INVALID_COOKIE
* S_bootpLib_INVALID_TAG
* S_bootpLib_PARSE_ERROR
*
* NOMANUAL
*/
u_char * bootpTagFind
(
u_char * pVend, /* vendor specific information */
int tag, /* tag to be located */
int * pSize /* return size of data */
)
{
u_char * cp; /* character pointer */
u_char * pData; /* pointer to data */
int sizeData; /* size if data */
if ( (pSize == NULL) || (pVend == NULL)) /* validate arguments */
{
errno = S_bootpLib_INVALID_ARGUMENT;
return (NULL);
}
if ( (tag <= TAG_PAD) || (tag >= TAG_END)) /* validate tag */
{
errno = S_bootpLib_INVALID_TAG;
return (NULL);
}
/* validate RFC 1048 cookie */
if (bcmp ( (char *)magicCookie1048, (char *)pVend,
sizeof (magicCookie1048)) != 0)
{
errno = S_bootpLib_INVALID_COOKIE;
return (NULL);
}
pData = pVend + sizeof (magicCookie1048); /* move past cookie */
sizeData = SIZE_VEND - sizeof (magicCookie1048);
/* loop to find tag */
for (cp = pData; (*cp != (u_char)TAG_END) && (cp < pData + sizeData); cp++)
{
if (*cp == (u_char) TAG_PAD) /* do nothing - pad */
continue;
if ( (cp + 1) >= (pData + sizeData)) /* no for length */
{
errno = S_bootpLib_PARSE_ERROR;
break;
}
*pSize = *(cp + 1);
/* no room for data */
if ( (cp + 2 + *pSize) > (pData + sizeData))
{
errno = S_bootpLib_PARSE_ERROR;
break;
}
if (*cp == (u_char)tag) /* found desired tag */
return (cp + 2);
cp += *pSize + 1; /* move past the data */
}
*pSize = 0;
return (NULL);
}