#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <syslog.h>
#include "bootp.h"
#include "bootpd.h"
#include "report.h"
#include "dovend.h"
PRIVATE int insert_generic(struct shared_bindata *, byte **, int *);
int
dovend_rfc1497(struct host *hp, byte *buf, int len)
{
int bytesleft = len;
byte *vp = buf;
static const char noroom[] = "%s: No room for \"%s\" option";
#define NEED(LEN, MSG) do \
if (bytesleft < (LEN)) { \
report(LOG_NOTICE, noroom, \
hp->hostname->string, MSG); \
return (vp - buf); \
} while (0)
if (hp->flags.time_offset) {
NEED(6, "to");
*vp++ = TAG_TIME_OFFSET;
*vp++ = 4;
insert_u_long(htonl(hp->time_offset), &vp);
bytesleft -= 6;
}
if (hp->flags.swap_server) {
NEED(6, "sw");
*vp++ = TAG_SWAP_SERVER;
*vp++ = 4;
insert_u_long(hp->swap_server.s_addr, &vp);
bytesleft -= 6;
}
if (hp->flags.root_path) {
len = strlen(hp->root_path->string);
NEED((len + 2), "rp");
*vp++ = TAG_ROOT_PATH;
*vp++ = (byte) (len & 0xFF);
bcopy(hp->root_path->string, vp, len);
vp += len;
bytesleft -= len + 2;
}
if (hp->flags.dump_file) {
len = strlen(hp->dump_file->string);
NEED((len + 2), "df");
*vp++ = TAG_DUMP_FILE;
*vp++ = (byte) (len & 0xFF);
bcopy(hp->dump_file->string, vp, len);
vp += len;
bytesleft -= len + 2;
}
if (hp->flags.domain_server) {
if (insert_ip(TAG_DOMAIN_SERVER,
hp->domain_server,
&vp, &bytesleft))
NEED(8, "ds");
}
if (hp->flags.domain_name) {
len = strlen(hp->domain_name->string);
NEED((len + 2), "dn");
*vp++ = TAG_DOMAIN_NAME;
*vp++ = (byte) (len & 0xFF);
bcopy(hp->domain_name->string, vp, len);
vp += len;
bytesleft -= len + 2;
}
if (hp->flags.nis_server) {
if (insert_ip(TAG_NIS_SERVER,
hp->nis_server,
&vp, &bytesleft))
NEED(8, "ys");
}
if (hp->flags.nis_domain) {
len = strlen(hp->nis_domain->string);
NEED((len + 2), "yn");
*vp++ = TAG_NIS_DOMAIN;
*vp++ = (byte) (len & 0xFF);
bcopy(hp->nis_domain->string, vp, len);
vp += len;
bytesleft -= len + 2;
}
if (hp->flags.name_server) {
if (insert_ip(TAG_NAME_SERVER,
hp->name_server,
&vp, &bytesleft))
NEED(8, "ns");
}
if (hp->flags.rlp_server) {
if (insert_ip(TAG_RLP_SERVER,
hp->rlp_server,
&vp, &bytesleft))
NEED(8, "rl");
}
if (hp->flags.time_server) {
if (insert_ip(TAG_TIME_SERVER,
hp->time_server,
&vp, &bytesleft))
NEED(8, "ts");
}
if (hp->flags.ntp_server) {
if (insert_ip(TAG_NTP_SERVER,
hp->ntp_server,
&vp, &bytesleft))
NEED(8, "nt");
}
if (hp->flags.name_switch && hp->flags.send_name) {
len = strlen(hp->hostname->string);
#if 0
if ((len + 2) > bytesleft) {
char *tmpstr = hp->hostname->string;
len = 0;
while (*tmpstr && (*tmpstr != '.')) {
tmpstr++;
len++;
}
}
#endif
NEED((len + 2), "hn");
*vp++ = TAG_HOST_NAME;
*vp++ = (byte) (len & 0xFF);
bcopy(hp->hostname->string, vp, len);
vp += len;
bytesleft -= len + 2;
}
if (hp->flags.lpr_server) {
if (insert_ip(TAG_LPR_SERVER,
hp->lpr_server,
&vp, &bytesleft))
NEED(8, "lp");
}
if (hp->flags.cookie_server) {
if (insert_ip(TAG_COOKIE_SERVER,
hp->cookie_server,
&vp, &bytesleft))
NEED(8, "cs");
}
if (hp->flags.log_server) {
if (insert_ip(TAG_LOG_SERVER,
hp->log_server,
&vp, &bytesleft))
NEED(8, "lg");
}
if (hp->flags.generic) {
if (insert_generic(hp->generic, &vp, &bytesleft))
NEED(64, "(generic)");
}
return (vp - buf);
#undef NEED
}
int
insert_ip(byte tag, struct in_addr_list *iplist, byte **dest, int *bytesleft)
{
struct in_addr *addrptr;
unsigned addrcount = 1;
byte *d;
if (iplist == NULL)
return (0);
if (*bytesleft >= 6) {
d = *dest;
**dest = tag;
(*dest) += 2;
(*bytesleft) -= 2;
addrptr = iplist->addr;
addrcount = iplist->addrcount;
while ((*bytesleft >= 4) && (addrcount > 0)) {
insert_u_long(addrptr->s_addr, dest);
addrptr++;
addrcount--;
(*bytesleft) -= 4;
}
d[1] = (byte) ((*dest - d - 2) & 0xFF);
}
return (addrcount);
}
static int
insert_generic(struct shared_bindata *gendata, byte **buff, int *bytesleft)
{
byte *srcptr;
int length, numbytes;
int skipped = 0;
if (gendata == NULL)
return (0);
srcptr = gendata->data;
length = gendata->length;
while ((length > 0) && (*bytesleft > 0)) {
switch (*srcptr) {
case TAG_END:
length = 0;
break;
case TAG_PAD:
*(*buff)++ = *srcptr++;
(*bytesleft)--;
length--;
break;
default:
numbytes = srcptr[1] + 2;
if (*bytesleft < numbytes)
skipped += numbytes;
else {
bcopy(srcptr, *buff, numbytes);
(*buff) += numbytes;
(*bytesleft) -= numbytes;
}
srcptr += numbytes;
length -= numbytes;
break;
}
}
return (skipped);
}
void
insert_u_long(u_int32 value, byte **dest)
{
byte *temp;
int n;
value = ntohl(value);
temp = (*dest += 4);
for (n = 4; n > 0; n--) {
*--temp = (byte) (value & 0xFF);
value >>= 8;
}
}