You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
694 lines
21 KiB
694 lines
21 KiB
/***************************************************************************/
|
|
/* */
|
|
/* Project: OpenSLP - OpenSource implementation of Service Location */
|
|
/* Protocol */
|
|
/* */
|
|
/* File: slp_dhcp.h */
|
|
/* */
|
|
/* Abstract: Implementation for functions that are related */
|
|
/* to acquiring specific dhcp parameters. */
|
|
/* */
|
|
/*-------------------------------------------------------------------------*/
|
|
/* */
|
|
/* Please submit patches to http://www.openslp.org */
|
|
/* */
|
|
/*-------------------------------------------------------------------------*/
|
|
/* */
|
|
/* Copyright (C) 2000 Caldera Systems, Inc */
|
|
/* All rights reserved. */
|
|
/* */
|
|
/* Redistribution and use in source and binary forms, with or without */
|
|
/* modification, are permitted provided that the following conditions are */
|
|
/* met: */
|
|
/* */
|
|
/* Redistributions of source code must retain the above copyright */
|
|
/* notice, this list of conditions and the following disclaimer. */
|
|
/* */
|
|
/* Redistributions in binary form must reproduce the above copyright */
|
|
/* notice, this list of conditions and the following disclaimer in */
|
|
/* the documentation and/or other materials provided with the */
|
|
/* distribution. */
|
|
/* */
|
|
/* Neither the name of Caldera Systems nor the names of its */
|
|
/* contributors may be used to endorse or promote products derived */
|
|
/* from this software without specific prior written permission. */
|
|
/* */
|
|
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
|
|
/* `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
|
|
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */
|
|
/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CALDERA */
|
|
/* SYSTEMS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
|
|
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
|
|
/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
|
|
/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
|
|
/* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
|
|
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
|
|
/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
|
|
/* */
|
|
/***************************************************************************/
|
|
|
|
#include "slp_dhcp.h"
|
|
#include "slp_message.h"
|
|
#include "slp_xmalloc.h"
|
|
|
|
#ifdef _WIN32
|
|
#include <winsock.h>
|
|
#include <windows.h>
|
|
#include <iphlpapi.h>
|
|
#define ETIMEDOUT 110
|
|
#define ENOTCONN 107
|
|
#else
|
|
/* non-win32 platforms close sockets with 'close' */
|
|
#define closesocket close
|
|
#include <unistd.h>
|
|
#include <netdb.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/ioctl.h>
|
|
#include <net/if_arp.h>
|
|
#include <sys/time.h>
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <errno.h>
|
|
|
|
/* UDP port numbers, server and client. */
|
|
#define IPPORT_BOOTPS 67
|
|
#define IPPORT_BOOTPC 68
|
|
|
|
/* BOOTP header op codes */
|
|
#define BOOTREQUEST 1
|
|
#define BOOTREPLY 2
|
|
|
|
/* BOOTP header field value maximums */
|
|
#define MAXHTYPES 7 /* Number of htypes defined */
|
|
#define MAXHADDRLEN 6 /* Max hw address length in bytes */
|
|
#define MAXSTRINGLEN 80 /* Max string length */
|
|
|
|
/* Some other useful constants */
|
|
#define MAX_MACADDR_SIZE 64 /* Max hardware address length */
|
|
#define MAX_DHCP_RETRIES 2 /* Max dhcp request retries */
|
|
|
|
/* timeout values */
|
|
#define USECS_PER_MSEC 1000
|
|
#define MSECS_PER_SEC 1000
|
|
#define USECS_PER_SEC (USECS_PER_MSEC * MSECS_PER_SEC)
|
|
#define INIT_TMOUT_USECS (250 * USECS_PER_MSEC)
|
|
|
|
/* DHCP vendor area cookie values */
|
|
#define DHCP_COOKIE1 99
|
|
#define DHCP_COOKIE2 130
|
|
#define DHCP_COOKIE3 83
|
|
#define DHCP_COOKIE4 99
|
|
|
|
/* DHCP Message Types for TAG_DHCP_MSG_TYPE */
|
|
#define DHCP_MSG_DISCOVER 1
|
|
#define DHCP_MSG_OFFER 2
|
|
#define DHCP_MSG_REQUEST 3
|
|
#define DHCP_MSG_DECLINE 4
|
|
#define DHCP_MSG_ACK 5
|
|
#define DHCP_MSG_NAK 6
|
|
#define DHCP_MSG_RELEASE 7
|
|
#define DHCP_MSG_INFORM 8
|
|
|
|
/*=========================================================================*/
|
|
static int dhcpCreateBCSkt(struct sockaddr_in* peeraddr)
|
|
/* Creates a socket and provides a broadcast addr to which DHCP requests
|
|
should be sent. Also binds the socket to the DHCP client port.
|
|
|
|
peeraddr (OUT) ptr to rcv addr to which DHCP requests are sent
|
|
|
|
Returns Valid socket or -1 if no DA connection can be made
|
|
=========================================================================*/
|
|
{
|
|
int sockfd;
|
|
#ifdef _WIN32
|
|
BOOL on = 1;
|
|
#else
|
|
int on = 1;
|
|
#endif
|
|
|
|
/* setup dhcp broadcast-to-server address structure */
|
|
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0)
|
|
{
|
|
struct sockaddr_in localaddr;
|
|
|
|
localaddr.sin_family = AF_INET;
|
|
localaddr.sin_port = htons(IPPORT_BOOTPC);
|
|
localaddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
|
if(bind(sockfd, (struct sockaddr*)&localaddr, sizeof(localaddr))
|
|
|| setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST,
|
|
(char*)&on, sizeof(on)))
|
|
{
|
|
closesocket(sockfd);
|
|
return -1;
|
|
}
|
|
peeraddr->sin_family = AF_INET;
|
|
peeraddr->sin_port = htons(IPPORT_BOOTPS);
|
|
peeraddr->sin_addr.s_addr = htonl(INADDR_BROADCAST);
|
|
}
|
|
return sockfd;
|
|
}
|
|
|
|
|
|
/*=========================================================================*/
|
|
static int dhcpSendRequest(int sockfd, void *buf, size_t bufsz,
|
|
struct sockaddr* peeraddr, struct timeval* timeout)
|
|
/* Sends a buffer to PEERADDR, times out after period specified in TIMEOUT
|
|
|
|
Returns - zero on success non-zero on failure
|
|
|
|
errno EPIPE error during write
|
|
ETIMEDOUT read timed out
|
|
=========================================================================*/
|
|
{
|
|
fd_set writefds;
|
|
int xferbytes;
|
|
int flags = 0;
|
|
|
|
#if defined(MSG_NOSIGNAL)
|
|
flags = MSG_NOSIGNAL;
|
|
#endif
|
|
|
|
FD_ZERO(&writefds);
|
|
FD_SET(sockfd, &writefds);
|
|
|
|
if((xferbytes = select(sockfd + 1, 0, &writefds, 0, timeout)) > 0)
|
|
{
|
|
if((xferbytes = sendto(sockfd, (char*)buf, (int)bufsz, flags,
|
|
peeraddr, sizeof(struct sockaddr_in))) <= 0)
|
|
{
|
|
errno = EPIPE;
|
|
return -1;
|
|
}
|
|
}
|
|
else if(xferbytes == 0)
|
|
{
|
|
errno = ETIMEDOUT;
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
errno = EPIPE;
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*=========================================================================*/
|
|
static int dhcpRecvResponse(int sockfd, void *buf, size_t bufsz,
|
|
struct timeval* timeout)
|
|
/* Receives a DHCP response from a DHCP server. Since DHCP responses are
|
|
broadcasts, we compare XID with received response to ensure we are
|
|
returning the correct response from a prior request.
|
|
|
|
Returns - zero on success, non-zero on failure
|
|
|
|
errno ENOTCONN error during read
|
|
ETIMEDOUT read timed out
|
|
=========================================================================*/
|
|
{
|
|
int xferbytes;
|
|
fd_set readfds;
|
|
|
|
FD_ZERO(&readfds);
|
|
FD_SET(sockfd, &readfds);
|
|
|
|
if((xferbytes = select(sockfd + 1, &readfds, 0 , 0, timeout)) > 0)
|
|
{
|
|
if((xferbytes = recvfrom(sockfd, (char*)buf, (int)bufsz, 0, 0, 0)) <= 0)
|
|
{
|
|
errno = ENOTCONN;
|
|
return -1;
|
|
}
|
|
return xferbytes;
|
|
}
|
|
else if(xferbytes == 0)
|
|
{
|
|
errno = ETIMEDOUT;
|
|
return -1;
|
|
}
|
|
errno = ENOTCONN;
|
|
return -1;
|
|
}
|
|
|
|
/*=========================================================================*/
|
|
static int dhcpProcessOptions(unsigned char *data, size_t datasz,
|
|
DHCPInfoCallBack *dhcpInfoCB, void *context)
|
|
/* Calls dhcpInfoCB once for each option returned by the dhcp server.
|
|
|
|
Returns - zero on success, non-zero on failure
|
|
|
|
errno ENOTCONN error during read
|
|
ETIME read timed out
|
|
ENOMEM out of memory
|
|
EINVAL parse error
|
|
=========================================================================*/
|
|
{
|
|
int err, taglen;
|
|
unsigned char tag;
|
|
|
|
/* validate vendor data header */
|
|
if(datasz < 4
|
|
|| *data++ != DHCP_COOKIE1 || *data++ != DHCP_COOKIE2
|
|
|| *data++ != DHCP_COOKIE3 || *data++ != DHCP_COOKIE4)
|
|
return -1; /* invalid dhcp response */
|
|
|
|
datasz -= 4; /* account for DHCP cookie values */
|
|
|
|
/* validate and process each tag in the vendor data */
|
|
while(datasz-- > 0 && (tag = *data++) != TAG_END)
|
|
{
|
|
if(tag != TAG_PAD)
|
|
{
|
|
if(!datasz-- || (taglen = *data++) > (int)datasz)
|
|
return -1; /* tag length greater than total data length */
|
|
|
|
if((err = dhcpInfoCB(tag, data, taglen, context)))
|
|
return err;
|
|
|
|
datasz -= taglen;
|
|
data += taglen;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*=========================================================================*/
|
|
static int dhcpGetAddressInfo(unsigned char *ipaddr, unsigned char *chaddr,
|
|
unsigned char *hlen, unsigned char *htype)
|
|
/* return hardware MAC address for specified ip address.
|
|
|
|
Returns - zero on success, non-zero on failure
|
|
=========================================================================*/
|
|
{
|
|
#ifdef _WIN32
|
|
|
|
HMODULE hmod;
|
|
DWORD (WINAPI *pGetAdaptersInfo)(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen);
|
|
char ipastr[16];
|
|
|
|
*hlen = 0;
|
|
|
|
sprintf(ipastr, "%d.%d.%d.%d", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
|
|
|
|
if((hmod = LoadLibrary("iphlpapi.dll")) != 0)
|
|
{
|
|
if((pGetAdaptersInfo = (DWORD(WINAPI *)(PIP_ADAPTER_INFO,PULONG))
|
|
GetProcAddress(hmod, "GetAdaptersInfo")) != 0)
|
|
{
|
|
DWORD dwerr;
|
|
ULONG bufsz = 0;
|
|
IP_ADAPTER_INFO *aip = 0;
|
|
if((dwerr = (*pGetAdaptersInfo)(aip, &bufsz)) == ERROR_BUFFER_OVERFLOW
|
|
&& (aip = (IP_ADAPTER_INFO *)xmalloc(bufsz)) != 0
|
|
&& (dwerr = (*pGetAdaptersInfo)(aip, &bufsz)) == ERROR_SUCCESS)
|
|
{
|
|
IP_ADAPTER_INFO *pcur;
|
|
for(pcur = aip; pcur && !*hlen; pcur = pcur->Next)
|
|
{
|
|
IP_ADDR_STRING *caddrp;
|
|
for(caddrp = &pcur->IpAddressList; caddrp && !*hlen; caddrp = caddrp->Next)
|
|
{
|
|
if(strcmp(ipastr, caddrp->IpAddress.String) == 0)
|
|
{
|
|
*hlen = pcur->AddressLength;
|
|
*htype = pcur->Type; /* win32 returns iana ARP values */
|
|
memcpy(chaddr, pcur->Address, pcur->AddressLength);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if(!*hlen) /* couldn't find the one we wanted, just use the first */
|
|
{
|
|
*hlen = aip->AddressLength;
|
|
*htype = aip->Type;
|
|
memcpy(chaddr, aip->Address, aip->AddressLength);
|
|
}
|
|
}
|
|
xfree(aip);
|
|
}
|
|
FreeLibrary(hmod);
|
|
}
|
|
|
|
#elif defined(SIOCGARP)
|
|
|
|
/* Query the ARP cache for our hardware address */
|
|
|
|
int sockfd;
|
|
struct arpreq arpreq;
|
|
struct sockaddr_in *sin;
|
|
|
|
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
|
|
return -1;
|
|
|
|
*hlen = 0;
|
|
|
|
sin = (struct sockaddr_in *)&arpreq.arp_pa;
|
|
memset(sin, 0, sizeof(struct sockaddr_in));
|
|
sin->sin_family = AF_INET;
|
|
memcpy(&sin->sin_addr, ipaddr, sizeof(struct in_addr));
|
|
|
|
if (ioctl(sockfd, SIOCGARP, &arpreq) >= 0
|
|
&& (arpreq.arp_flags & ATF_COM))
|
|
{
|
|
*hlen = 6; /* assume IEEE802 compatible */
|
|
*htype = arpreq.arp_ha.sa_family;
|
|
memcpy(chaddr, arpreq.arp_ha.sa_data, 6);
|
|
}
|
|
closesocket(sockfd);
|
|
|
|
#else
|
|
/* figure out another way ... */
|
|
|
|
(void)ipaddr;
|
|
(void)chaddr;
|
|
(void)htype;
|
|
|
|
*hlen = 0;
|
|
|
|
#endif
|
|
|
|
return *hlen? 0: -1;
|
|
}
|
|
|
|
|
|
/*=========================================================================*/
|
|
int DHCPGetOptionInfo(unsigned char *dhcpOptCodes, int dhcpOptCodeCnt,
|
|
DHCPInfoCallBack *dhcpInfoCB, void *context)
|
|
/* Calls dhcpInfoCB once for each requested option in dhcpOptCodes.
|
|
|
|
Returns - zero on success, non-zero on failure
|
|
|
|
errno ENOTCONN error during read
|
|
ETIME read timed out
|
|
ENOMEM out of memory
|
|
EINVAL parse error
|
|
|
|
BOOTP/DHCP packet header format:
|
|
|
|
Offs Len Name Description
|
|
0 1 opcode Message opcode: 1 = BOOTREQUEST, 2 = BOOTREPLY
|
|
1 1 htype Hardware address type (eg., 1 = 10mb ethernet)
|
|
2 1 hlen Hardware address length (eg., 6 = 10mb ethernet)
|
|
3 1 hops Client sets to zero, optionally used by relay agents
|
|
4 4 xid Transaction ID, random number chosen by client
|
|
8 2 secs Client sets to seconds since start of boot process
|
|
10 2 flags Bit 0: broadcast response bit
|
|
12 4 ciaddr Client IP address - only filled if client is bound
|
|
16 4 yiaddr 'your' (Client) IP address
|
|
20 4 siaddr IP address of next server to use in bootstrap
|
|
24 4 giaddr Relay agent IP address, used in booting via RA
|
|
28 16 chaddr Client hardware address
|
|
44 64 sname Optional server host name, null-terminated string
|
|
108 128 file Boot file name, null-terminated string
|
|
236 var options Optional parameters field
|
|
|
|
The options field has the following format:
|
|
|
|
Offs Len Name Description
|
|
0 4 cookie 4-byte cookie field: 99.130.83.99 (0x63825363)
|
|
|
|
Followed by 1-byte option codes and 1-byte option lengths, except
|
|
for the two special fixed length options, pad (0) and end (255).
|
|
Options are defined in slp_dhcp.h as TAG_XXX values. The two we
|
|
really care about here are options TAG_SLP_DA and TAG_SLP_SCOPE,
|
|
78 and 79, respectively.
|
|
|
|
The format for TAG_SLP_DA (starting with the tag) is:
|
|
|
|
Offs Len Name Description
|
|
0 1 tag TAG_SLP_DA - directory agent ip addresses
|
|
1 1 length length of remaining data in the option
|
|
2 1 mand flag: the use of these DA's is mandatory
|
|
3 4 a(0) 4-byte ip address
|
|
...
|
|
3+n*4 4 a(n) 4-byte ip address
|
|
|
|
The format for TAG_SLP_SCOPE (starting with the tag) is:
|
|
|
|
Offs Len Name Description
|
|
0 1 tag TAG_SLP_SCOPE - directory scopes to use
|
|
1 1 length length of remaining data in the option
|
|
2 1 mand flag: the use of these scopes is mandatory
|
|
3 var scopes a null-terminated, comma-separated string of scopes
|
|
|
|
The "DHCP Message Type" option must be included in every DHCP message.
|
|
All tags except for TAG_PAD(0) and TAG_END(255) begin with a tag value
|
|
followed by a length of remaining data value.
|
|
=========================================================================*/
|
|
{
|
|
UINT32 xid;
|
|
time_t timer;
|
|
struct timeval tv;
|
|
int sockfd, retries;
|
|
struct sockaddr_in sendaddr;
|
|
unsigned char chaddr[MAX_MACADDR_SIZE];
|
|
unsigned char hlen, htype;
|
|
unsigned char sndbuf[512];
|
|
unsigned char rcvbuf[512];
|
|
struct hostent *hep;
|
|
unsigned char *p;
|
|
size_t rcvbufsz = 0;
|
|
char host[256];
|
|
|
|
/* Get our IP and MAC addresses */
|
|
if(gethostname(host, (int)sizeof(host))
|
|
|| !(hep = gethostbyname(host))
|
|
|| dhcpGetAddressInfo((unsigned char *)hep->h_addr,
|
|
chaddr, &hlen, &htype))
|
|
return -1;
|
|
|
|
/* get a reasonably random transaction id value */
|
|
xid = (UINT32)time(&timer);
|
|
|
|
/* BOOTP request header */
|
|
memset(sndbuf, 0, 236); /* clear bootp header */
|
|
p = sndbuf;
|
|
*p++ = BOOTREQUEST; /* opcode */
|
|
*p++ = htype;
|
|
*p++ = hlen;
|
|
p++; /* hops */
|
|
ToUINT32(p, xid);
|
|
p += 2 * sizeof(UINT32); /* xid, secs, flags */
|
|
memcpy(p, hep->h_addr, 4);
|
|
p += 4 * sizeof(UINT32); /* ciaddr, yiaddr, siaddr, giaddr */
|
|
memcpy(p, chaddr, hlen);
|
|
p += 16 + 64 + 128; /* chaddr, sname and file */
|
|
*p++ = DHCP_COOKIE1; /* options, cookies 1-4 */
|
|
*p++ = DHCP_COOKIE2;
|
|
*p++ = DHCP_COOKIE3;
|
|
*p++ = DHCP_COOKIE4;
|
|
|
|
/* DHCP Message Type option */
|
|
*p++ = TAG_DHCP_MSG_TYPE;
|
|
*p++ = 1; /* option length */
|
|
*p++ = DHCP_MSG_INFORM; /* message type is DHCPINFORM */
|
|
|
|
/* DHCP Parameter Request option */
|
|
*p++ = TAG_DHCP_PARAM_REQ; /* request for DHCP parms */
|
|
*p++ = (unsigned char)dhcpOptCodeCnt;
|
|
memcpy(p, dhcpOptCodes, dhcpOptCodeCnt);
|
|
p += dhcpOptCodeCnt;
|
|
|
|
/* DHCP Client Identifier option */
|
|
*p++ = TAG_CLIENT_IDENTIFIER;
|
|
*p++ = hlen + 1; /* option length */
|
|
*p++ = htype; /* client id is htype/haddr */
|
|
memcpy(p, chaddr, hlen);
|
|
p += hlen;
|
|
|
|
/* End option */
|
|
*p++ = TAG_END;
|
|
|
|
/* get a broadcast send/recv socket and address */
|
|
if((sockfd = dhcpCreateBCSkt(&sendaddr)) < 0)
|
|
return -1;
|
|
|
|
/* setup select timeout */
|
|
tv.tv_sec = 0;
|
|
tv.tv_usec = INIT_TMOUT_USECS;
|
|
|
|
retries = 0;
|
|
srand((unsigned)time(&timer));
|
|
while (retries++ < MAX_DHCP_RETRIES)
|
|
{
|
|
if(dhcpSendRequest(sockfd, sndbuf, p - sndbuf,
|
|
(struct sockaddr *)&sendaddr, &tv) < 0)
|
|
{
|
|
if (errno != ETIMEDOUT)
|
|
{
|
|
closesocket(sockfd);
|
|
return -1;
|
|
}
|
|
}
|
|
else if((rcvbufsz = dhcpRecvResponse(sockfd, rcvbuf,
|
|
sizeof(rcvbuf), &tv)) < 0)
|
|
{
|
|
if (errno != ETIMEDOUT)
|
|
{
|
|
closesocket(sockfd);
|
|
return -1;
|
|
}
|
|
}
|
|
else if(rcvbufsz >= 236 && AsUINT32(&rcvbuf[4]) == xid)
|
|
break;
|
|
|
|
/* exponential backoff randomized by a
|
|
uniform number between -1 and 1 */
|
|
tv.tv_usec = tv.tv_usec * 2 + (rand() % 3) - 1;
|
|
tv.tv_sec = tv.tv_usec / USECS_PER_SEC;
|
|
tv.tv_usec %= USECS_PER_SEC;
|
|
}
|
|
closesocket(sockfd);
|
|
return rcvbufsz? dhcpProcessOptions(rcvbuf + 236, rcvbufsz - 236,
|
|
dhcpInfoCB, context): -1;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
int DHCPParseSLPTags(int tag, void *optdata, size_t optdatasz, void *context)
|
|
/* Callback routined tests each DA discovered from DHCP and add it to the */
|
|
/* DA cache. */
|
|
/* */
|
|
/* Returns: 0 on success, or nonzero to stop being called. */
|
|
/*-------------------------------------------------------------------------*/
|
|
{
|
|
int cpysz, bufsz;
|
|
DHCPContext *ctxp = (DHCPContext *)context;
|
|
unsigned char *p = (unsigned char *)optdata;
|
|
unsigned char flags, dasize;
|
|
int encoding;
|
|
|
|
/* filter out zero length options */
|
|
if (!optdatasz)
|
|
return 0;
|
|
|
|
switch(tag)
|
|
{
|
|
case TAG_SLP_SCOPE:
|
|
|
|
/* Draft 3 format is only supported for ASCII and UNICODE
|
|
character encodings - UTF8 encodings must use rfc2610 format.
|
|
To determine the format, we parse 2 bytes and see if the result
|
|
is a valid encoding. If so it's draft 3, otherwise rfc2610. */
|
|
|
|
encoding = (optdatasz > 1)? AsUINT16(p): 0;
|
|
if (encoding != CT_ASCII && encoding != CT_UNICODE)
|
|
{
|
|
/* rfc2610 format */
|
|
|
|
if (optdatasz == 1)
|
|
break; /* UA's should ignore statically configured
|
|
scopes for this interface -
|
|
add code to handle this later...
|
|
*/
|
|
|
|
flags = *p++; /* pick up the mandatory flag... */
|
|
optdatasz--;
|
|
|
|
if (flags)
|
|
; /* ...and add code to handle it later... */
|
|
|
|
/* copy utf8 string into return buffer */
|
|
cpysz = optdatasz < sizeof(ctxp->scopelist)?
|
|
optdatasz: sizeof(ctxp->scopelist);
|
|
strncpy(ctxp->scopelist, (char*)p, cpysz);
|
|
ctxp->scopelist[sizeof(ctxp->scopelist) - 1] = 0;
|
|
}
|
|
else
|
|
{
|
|
/* draft 3 format: defined to configure scopes for SA's only
|
|
so we should flag the scopes to be used only as registration
|
|
filter scopes - add code to handle this case later...
|
|
|
|
offs len name description
|
|
0 2 encoding character encoding used
|
|
2 n scopelist list of scopes as asciiz string.
|
|
|
|
*/
|
|
|
|
optdatasz -= 2; /* skip encoding bytes */
|
|
p += 2;
|
|
|
|
/* if UNICODE encoding is used convert to utf8 */
|
|
if (encoding == CT_UNICODE)
|
|
wcstombs(ctxp->scopelist, (wchar_t*)p, sizeof(ctxp->scopelist));
|
|
else
|
|
{
|
|
cpysz = optdatasz < sizeof(ctxp->scopelist)?
|
|
optdatasz: sizeof(ctxp->scopelist);
|
|
strncpy(ctxp->scopelist, (char*)p, cpysz);
|
|
ctxp->scopelist[sizeof(ctxp->scopelist) - 1] = 0;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TAG_SLP_DA:
|
|
flags = *p++;
|
|
optdatasz--;
|
|
|
|
/* If the flags byte has the high bit set, we know we are
|
|
using draft 3 format, otherwise rfc2610 format. */
|
|
|
|
if (!(flags & DA_NAME_PRESENT))
|
|
{
|
|
/* rfc2610 format */
|
|
if (flags)
|
|
{
|
|
/* If the mandatory byte is non-zero, indicate that
|
|
multicast is not to be used to dynamically discover
|
|
directory agents on this interface by setting the
|
|
LACBF_STATIC_DA flag in the LACB for this interface. */
|
|
|
|
/* skip this for now - deal with it later... */
|
|
}
|
|
|
|
bufsz = sizeof(ctxp->addrlist) - ctxp->addrlistlen;
|
|
cpysz = (int)optdatasz < bufsz? optdatasz: bufsz;
|
|
memcpy(ctxp->addrlist + ctxp->addrlistlen, p, cpysz);
|
|
ctxp->addrlistlen += cpysz;
|
|
}
|
|
else
|
|
{
|
|
/* pre-rfc2610 (draft 3) format:
|
|
offs len name description
|
|
0 1 flags contains 4 flags (defined above)
|
|
1 1 dasize name or addr length
|
|
2 dasize daname da name or ip address (flags)
|
|
*/
|
|
dasize = *p++;
|
|
optdatasz--;
|
|
|
|
if (dasize > optdatasz)
|
|
dasize = optdatasz;
|
|
if (flags & DA_NAME_IS_DNS)
|
|
; /* DA name contains dns name - we have to resolve - later... */
|
|
else
|
|
{ /* DA name is one 4-byte ip address */
|
|
if (dasize < 4)
|
|
break; /* oops, bad option format */
|
|
dasize = 4;
|
|
bufsz = sizeof(ctxp->addrlist) - ctxp->addrlistlen;
|
|
cpysz = dasize < bufsz? dasize: bufsz;
|
|
memcpy(ctxp->addrlist + ctxp->addrlistlen, p, cpysz);
|
|
ctxp->addrlistlen += cpysz;
|
|
}
|
|
if (flags & DISABLE_DA_MCAST)
|
|
; /* this is the equivalent of the rfc2610 mandatory bit */
|
|
}
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|