Enable use of DHCP extensions.

Reviewed by:	Per Kristian Hove <Per.Hove@math.ntnu.no>
This commit is contained in:
Tor Egge 2001-02-02 02:35:40 +00:00
parent ed4f8196d0
commit 7d1af7b215
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=71915
2 changed files with 480 additions and 66 deletions

View File

@ -126,10 +126,15 @@ struct bootpc_ifcontext {
enum {
IF_BOOTP_UNRESOLVED,
IF_BOOTP_RESOLVED,
IF_BOOTP_FAILED,
IF_DHCP_UNRESOLVED,
IF_DHCP_OFFERED,
IF_DHCP_RESOLVED,
IF_BOOTP_FAILED
IF_DHCP_FAILED,
} state;
int dhcpquerytype; /* dhcp type sent */
struct in_addr dhcpserver;
int gotdhcpserver;
};
#define TAG_MAXLEN 1024
@ -191,6 +196,17 @@ struct bootpc_globalcontext {
#define TAG_ROOTOPTS 130
#define TAG_SWAPOPTS 131
#define TAG_DHCP_MSGTYPE 53
#define TAG_DHCP_REQ_ADDR 50
#define TAG_DHCP_SERVERID 54
#define TAG_DHCP_LEASETIME 51
#define DHCP_NOMSG 0
#define DHCP_DISCOVER 1
#define DHCP_OFFER 2
#define DHCP_REQUEST 3
#define DHCP_ACK 5
extern int nfs_diskless_valid;
extern struct nfsv3_diskless nfsv3_diskless;
@ -249,6 +265,10 @@ static void bootpc_decode_reply(struct nfsv3_diskless *nd,
static int bootpc_received(struct bootpc_globalcontext *gctx,
struct bootpc_ifcontext *ifctx);
static __inline int bootpc_ifctx_isresolved(struct bootpc_ifcontext *ifctx);
static __inline int bootpc_ifctx_isunresolved(struct bootpc_ifcontext *ifctx);
static __inline int bootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx);
void bootpc_init(void);
/*
@ -418,15 +438,52 @@ allocifctx(struct bootpc_globalcontext *gctx)
bzero(ifctx, sizeof(*ifctx));
ifctx->xid = gctx->xid;
#ifdef BOOTP_NO_DHCP
ifctx->state = IF_BOOTP_UNRESOLVED;
#else
ifctx->state = IF_DHCP_UNRESOLVED;
#endif
gctx->xid += 0x100;
return ifctx;
}
static __inline int
bootpc_ifctx_isresolved(struct bootpc_ifcontext *ifctx)
{
if (ifctx->state == IF_BOOTP_RESOLVED ||
ifctx->state == IF_DHCP_RESOLVED)
return 1;
return 0;
}
static __inline int
bootpc_ifctx_isunresolved(struct bootpc_ifcontext *ifctx)
{
if (ifctx->state == IF_BOOTP_UNRESOLVED ||
ifctx->state == IF_DHCP_UNRESOLVED)
return 1;
return 0;
}
static __inline int
bootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx)
{
if (ifctx->state == IF_BOOTP_FAILED ||
ifctx->state == IF_DHCP_FAILED)
return 1;
return 0;
}
static int
bootpc_received(struct bootpc_globalcontext *gctx,
struct bootpc_ifcontext *ifctx)
{
unsigned char dhcpreplytype;
char *p;
/*
* Need timeout for fallback to less
* desirable alternative.
@ -442,9 +499,35 @@ bootpc_received(struct bootpc_globalcontext *gctx,
if (gctx->tmptag.badopt != 0)
return 0;
p = bootpc_tag(&gctx->tmptag, &gctx->reply,
gctx->replylen, TAG_DHCP_MSGTYPE);
if (p != NULL)
dhcpreplytype = *p;
else
dhcpreplytype = DHCP_NOMSG;
switch (ifctx->dhcpquerytype) {
case DHCP_DISCOVER:
if (dhcpreplytype != DHCP_OFFER /* Normal DHCP offer */
#ifndef BOOTP_FORCE_DHCP
&& dhcpreplytype != DHCP_NOMSG /* Fallback to BOOTP */
#endif
)
return 0;
break;
case DHCP_REQUEST:
if (dhcpreplytype != DHCP_ACK)
return 0;
case DHCP_NOMSG:
}
/* Ignore packet unless it gives us a root tag we didn't have */
if (ifctx->state == IF_BOOTP_RESOLVED &&
if ((ifctx->state == IF_BOOTP_RESOLVED ||
(ifctx->dhcpquerytype == DHCP_DISCOVER &&
(ifctx->state == IF_DHCP_OFFERED ||
ifctx->state == IF_DHCP_RESOLVED))) &&
(bootpc_tag(&gctx->tmptag, &ifctx->reply,
ifctx->replylen,
TAG_ROOT) != NULL ||
@ -459,7 +542,31 @@ bootpc_received(struct bootpc_globalcontext *gctx,
ifctx->replylen = gctx->replylen;
/* XXX: Only reset if 'perfect' response */
ifctx->state = IF_BOOTP_RESOLVED;
if (ifctx->state == IF_BOOTP_UNRESOLVED)
ifctx->state = IF_BOOTP_RESOLVED;
else if (ifctx->state == IF_DHCP_UNRESOLVED &&
ifctx->dhcpquerytype == DHCP_DISCOVER) {
if (dhcpreplytype == DHCP_OFFER)
ifctx->state = IF_DHCP_OFFERED;
else
ifctx->state = IF_BOOTP_RESOLVED; /* Fallback */
} else if (ifctx->state == IF_DHCP_OFFERED &&
ifctx->dhcpquerytype == DHCP_REQUEST)
ifctx->state = IF_DHCP_RESOLVED;
if (ifctx->dhcpquerytype == DHCP_DISCOVER &&
ifctx->state != IF_BOOTP_RESOLVED) {
p = bootpc_tag(&gctx->tmptag, &ifctx->reply,
ifctx->replylen, TAG_DHCP_SERVERID);
if (p != NULL && gctx->tmptag.taglen == 4) {
memcpy(&ifctx->dhcpserver, p, 4);
ifctx->gotdhcpserver = 1;
} else
ifctx->gotdhcpserver = 0;
return 1;
}
ifctx->gotrootpath = (bootpc_tag(&gctx->tmptag, &ifctx->reply,
ifctx->replylen,
TAG_ROOT) != NULL);
@ -488,6 +595,8 @@ bootpc_call(struct bootpc_globalcontext *gctx,
struct bootpc_ifcontext *ifctx;
int outstanding;
int gotrootpath;
int retry;
const char *s;
/*
* Create socket and set its recieve timeout.
@ -568,7 +677,7 @@ bootpc_call(struct bootpc_globalcontext *gctx,
for (ifctx = gctx->interfaces;
ifctx != NULL;
ifctx = ifctx->next) {
if (ifctx->state == IF_BOOTP_RESOLVED &&
if (bootpc_ifctx_isresolved(ifctx) != 0 &&
bootpc_tag(&gctx->tmptag, &ifctx->reply,
ifctx->replylen,
TAG_ROOT) != NULL)
@ -579,21 +688,45 @@ bootpc_call(struct bootpc_globalcontext *gctx,
ifctx != NULL;
ifctx = ifctx->next) {
ifctx->outstanding = 0;
if (ifctx->state == IF_BOOTP_RESOLVED &&
if (bootpc_ifctx_isresolved(ifctx) != 0 &&
gotrootpath != 0) {
continue;
}
if (ifctx->state == IF_BOOTP_FAILED)
if (bootpc_ifctx_isfailed(ifctx) != 0)
continue;
outstanding++;
ifctx->outstanding = 1;
/* Proceed to next step in DHCP negotiation */
if ((ifctx->state == IF_DHCP_OFFERED &&
ifctx->dhcpquerytype != DHCP_REQUEST) ||
(ifctx->state == IF_DHCP_UNRESOLVED &&
ifctx->dhcpquerytype != DHCP_DISCOVER) ||
(ifctx->state == IF_BOOTP_UNRESOLVED &&
ifctx->dhcpquerytype != DHCP_NOMSG)) {
ifctx->sentmsg = 0;
bootpc_compose_query(ifctx, gctx, procp);
}
/* Send BOOTP request (or re-send). */
if (ifctx->sentmsg == 0) {
printf("Sending BOOTP Query packet from "
switch(ifctx->dhcpquerytype) {
case DHCP_DISCOVER:
s = "DHCP Discover";
break;
case DHCP_REQUEST:
s = "DHCP Request";
break;
case DHCP_NOMSG:
default:
s = "BOOTP Query";
break;
}
printf("Sending %s packet from "
"interface %s (%*D)\n",
s,
ifctx->ireq.ifr_name,
ifctx->sdl->sdl_alen,
(unsigned char *) LLADDR(ifctx->sdl),
@ -657,7 +790,7 @@ bootpc_call(struct bootpc_globalcontext *gctx,
if (timo < MAX_RESEND_DELAY)
timo++;
else {
printf("BOOTP timeout for server ");
printf("DHCP/BOOTP timeout for server ");
print_sin_addr(&dst);
printf("\n");
}
@ -686,10 +819,10 @@ bootpc_call(struct bootpc_globalcontext *gctx,
for (ifctx = gctx->interfaces;
ifctx != NULL;
ifctx = ifctx->next) {
if (ifctx->state == IF_BOOTP_RESOLVED)
continue;
if (ifctx->state == IF_BOOTP_FAILED)
if (bootpc_ifctx_isresolved(ifctx) != 0 ||
bootpc_ifctx_isfailed(ifctx) != 0)
continue;
ifctx->call.secs = htons(gctx->secs);
}
if (error == EWOULDBLOCK)
@ -728,8 +861,28 @@ bootpc_call(struct bootpc_globalcontext *gctx,
}
if (ifctx != NULL) {
printf("Received BOOTP Reply packet"
s = bootpc_tag(&gctx->tmptag,
&gctx->reply,
gctx->replylen,
TAG_DHCP_MSGTYPE);
if (s != NULL) {
switch (*s) {
case DHCP_OFFER:
s = "DHCP Offer";
break;
case DHCP_ACK:
s = "DHCP Ack";
break;
default:
s = "DHCP (unexpected)";
break;
}
} else
s = "BOOTP Reply";
printf("Received %s packet"
" on %s from ",
s,
ifctx->ireq.ifr_name);
print_in_addr(gctx->reply.siaddr);
if (gctx->reply.giaddr.s_addr !=
@ -763,6 +916,21 @@ bootpc_call(struct bootpc_globalcontext *gctx,
if (gctx->secs > BOOTP_TIMEOUT && BOOTP_TIMEOUT > 0)
break;
#endif
/* Force a retry if halfway in DHCP negotiation */
retry = 0;
for (ifctx = gctx->interfaces; ifctx != NULL;
ifctx = ifctx->next) {
if (ifctx->state == IF_DHCP_OFFERED) {
if (ifctx->dhcpquerytype == DHCP_DISCOVER)
retry = 1;
else
ifctx->state = IF_DHCP_UNRESOLVED;
}
}
if (retry != 0)
continue;
if (gotrootpath != 0) {
gctx->gotrootpath = gotrootpath;
if (rtimo != 0 && time_second >= rtimo)
@ -776,8 +944,10 @@ bootpc_call(struct bootpc_globalcontext *gctx,
*/
for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) {
if (ifctx->state != IF_BOOTP_RESOLVED) {
printf("BOOTP timeout for interface %s\n",
if (bootpc_ifctx_isresolved(ifctx) == 0) {
printf("%s timeout for interface %s\n",
ifctx->dhcpquerytype != DHCP_NOMSG ?
"DHCP" : "BOOTP",
ifctx->ireq.ifr_name);
}
}
@ -790,7 +960,7 @@ bootpc_call(struct bootpc_globalcontext *gctx,
}
#ifndef BOOTP_NFSROOT
for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) {
if (ifctx->state == IF_BOOTP_RESOLVED) {
if (bootpc_ifctx_isresolved(ifctx) != 0) {
error = 0;
goto out;
}
@ -920,7 +1090,7 @@ bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
netmask = &ifctx->netmask;
gw = &ifctx->gw;
if (ifctx->state != IF_BOOTP_RESOLVED) {
if (bootpc_ifctx_isresolved(ifctx) == 0) {
/* Shutdown interfaces where BOOTP failed */
@ -1161,12 +1331,11 @@ bootpc_compose_query(ifctx, gctx, procp)
struct bootpc_globalcontext *gctx;
struct proc *procp;
{
gctx->gotrootpath = 0;
gctx->gotswappath = 0;
gctx->gotgw = 0;
unsigned char *vendp;
uint32_t leasetime;
ifctx->gotrootpath = 0;
bzero((caddr_t) &ifctx->call, sizeof(ifctx->call));
/* bootpc part */
@ -1174,19 +1343,53 @@ bootpc_compose_query(ifctx, gctx, procp)
ifctx->call.htype = 1; /* 10mb ethernet */
ifctx->call.hlen = ifctx->sdl->sdl_alen;/* Hardware address length */
ifctx->call.hops = 0;
ifctx->xid++;
if (bootpc_ifctx_isunresolved(ifctx) != 0)
ifctx->xid++;
ifctx->call.xid = txdr_unsigned(ifctx->xid);
bcopy(LLADDR(ifctx->sdl), &ifctx->call.chaddr, ifctx->sdl->sdl_alen);
ifctx->call.vend[0] = 99; /* RFC1048 cookie */
ifctx->call.vend[1] = 130;
ifctx->call.vend[2] = 83;
ifctx->call.vend[3] = 99;
ifctx->call.vend[4] = TAG_MAXMSGSIZE;
ifctx->call.vend[5] = 2;
ifctx->call.vend[6] = (sizeof(struct bootp_packet) >> 8) & 255;
ifctx->call.vend[7] = sizeof(struct bootp_packet) & 255;
ifctx->call.vend[8] = TAG_END;
vendp = ifctx->call.vend;
*vendp++ = 99; /* RFC1048 cookie */
*vendp++ = 130;
*vendp++ = 83;
*vendp++ = 99;
*vendp++ = TAG_MAXMSGSIZE;
*vendp++ = 2;
*vendp++ = (sizeof(struct bootp_packet) >> 8) & 255;
*vendp++ = sizeof(struct bootp_packet) & 255;
ifctx->dhcpquerytype = DHCP_NOMSG;
switch (ifctx->state) {
case IF_DHCP_UNRESOLVED:
*vendp++ = TAG_DHCP_MSGTYPE;
*vendp++ = 1;
*vendp++ = DHCP_DISCOVER;
ifctx->dhcpquerytype = DHCP_DISCOVER;
ifctx->gotdhcpserver = 0;
break;
case IF_DHCP_OFFERED:
*vendp++ = TAG_DHCP_MSGTYPE;
*vendp++ = 1;
*vendp++ = DHCP_REQUEST;
ifctx->dhcpquerytype = DHCP_REQUEST;
*vendp++ = TAG_DHCP_REQ_ADDR;
*vendp++ = 4;
memcpy(vendp, &ifctx->reply.yiaddr, 4);
vendp += 4;
if (ifctx->gotdhcpserver != 0) {
*vendp++ = TAG_DHCP_SERVERID;
*vendp++ = 4;
memcpy(vendp, &ifctx->dhcpserver, 4);
vendp += 4;
}
*vendp++ = TAG_DHCP_LEASETIME;
*vendp++ = 4;
leasetime = htonl(300);
memcpy(vendp, &leasetime, 4);
vendp += 4;
default:
;
}
*vendp = TAG_END;
ifctx->call.secs = 0;
ifctx->call.flags = htons(0x8000); /* We need an broadcast answer */
@ -1537,6 +1740,10 @@ bootpc_init(void)
#endif
}
gctx->gotrootpath = 0;
gctx->gotswappath = 0;
gctx->gotgw = 0;
for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
bootpc_fakeup_interface(ifctx, gctx, procp);
@ -1559,7 +1766,7 @@ bootpc_init(void)
mountopts(&nd->swap_args, NULL);
for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
if (ifctx->state == IF_BOOTP_RESOLVED)
if (bootpc_ifctx_isresolved(ifctx) != 0)
bootpc_decode_reply(nd, ifctx, gctx);
if (gctx->gotswappath == 0)
@ -1582,7 +1789,7 @@ bootpc_init(void)
for (ifctx = gctx->interfaces;
ifctx != NULL;
ifctx = ifctx->next)
if (ifctx->state == IF_BOOTP_RESOLVED)
if (bootpc_ifctx_isresolved(ifctx) != 0)
break;
}
if (ifctx == NULL)

View File

@ -126,10 +126,15 @@ struct bootpc_ifcontext {
enum {
IF_BOOTP_UNRESOLVED,
IF_BOOTP_RESOLVED,
IF_BOOTP_FAILED,
IF_DHCP_UNRESOLVED,
IF_DHCP_OFFERED,
IF_DHCP_RESOLVED,
IF_BOOTP_FAILED
IF_DHCP_FAILED,
} state;
int dhcpquerytype; /* dhcp type sent */
struct in_addr dhcpserver;
int gotdhcpserver;
};
#define TAG_MAXLEN 1024
@ -191,6 +196,17 @@ struct bootpc_globalcontext {
#define TAG_ROOTOPTS 130
#define TAG_SWAPOPTS 131
#define TAG_DHCP_MSGTYPE 53
#define TAG_DHCP_REQ_ADDR 50
#define TAG_DHCP_SERVERID 54
#define TAG_DHCP_LEASETIME 51
#define DHCP_NOMSG 0
#define DHCP_DISCOVER 1
#define DHCP_OFFER 2
#define DHCP_REQUEST 3
#define DHCP_ACK 5
extern int nfs_diskless_valid;
extern struct nfsv3_diskless nfsv3_diskless;
@ -249,6 +265,10 @@ static void bootpc_decode_reply(struct nfsv3_diskless *nd,
static int bootpc_received(struct bootpc_globalcontext *gctx,
struct bootpc_ifcontext *ifctx);
static __inline int bootpc_ifctx_isresolved(struct bootpc_ifcontext *ifctx);
static __inline int bootpc_ifctx_isunresolved(struct bootpc_ifcontext *ifctx);
static __inline int bootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx);
void bootpc_init(void);
/*
@ -418,15 +438,52 @@ allocifctx(struct bootpc_globalcontext *gctx)
bzero(ifctx, sizeof(*ifctx));
ifctx->xid = gctx->xid;
#ifdef BOOTP_NO_DHCP
ifctx->state = IF_BOOTP_UNRESOLVED;
#else
ifctx->state = IF_DHCP_UNRESOLVED;
#endif
gctx->xid += 0x100;
return ifctx;
}
static __inline int
bootpc_ifctx_isresolved(struct bootpc_ifcontext *ifctx)
{
if (ifctx->state == IF_BOOTP_RESOLVED ||
ifctx->state == IF_DHCP_RESOLVED)
return 1;
return 0;
}
static __inline int
bootpc_ifctx_isunresolved(struct bootpc_ifcontext *ifctx)
{
if (ifctx->state == IF_BOOTP_UNRESOLVED ||
ifctx->state == IF_DHCP_UNRESOLVED)
return 1;
return 0;
}
static __inline int
bootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx)
{
if (ifctx->state == IF_BOOTP_FAILED ||
ifctx->state == IF_DHCP_FAILED)
return 1;
return 0;
}
static int
bootpc_received(struct bootpc_globalcontext *gctx,
struct bootpc_ifcontext *ifctx)
{
unsigned char dhcpreplytype;
char *p;
/*
* Need timeout for fallback to less
* desirable alternative.
@ -442,9 +499,35 @@ bootpc_received(struct bootpc_globalcontext *gctx,
if (gctx->tmptag.badopt != 0)
return 0;
p = bootpc_tag(&gctx->tmptag, &gctx->reply,
gctx->replylen, TAG_DHCP_MSGTYPE);
if (p != NULL)
dhcpreplytype = *p;
else
dhcpreplytype = DHCP_NOMSG;
switch (ifctx->dhcpquerytype) {
case DHCP_DISCOVER:
if (dhcpreplytype != DHCP_OFFER /* Normal DHCP offer */
#ifndef BOOTP_FORCE_DHCP
&& dhcpreplytype != DHCP_NOMSG /* Fallback to BOOTP */
#endif
)
return 0;
break;
case DHCP_REQUEST:
if (dhcpreplytype != DHCP_ACK)
return 0;
case DHCP_NOMSG:
}
/* Ignore packet unless it gives us a root tag we didn't have */
if (ifctx->state == IF_BOOTP_RESOLVED &&
if ((ifctx->state == IF_BOOTP_RESOLVED ||
(ifctx->dhcpquerytype == DHCP_DISCOVER &&
(ifctx->state == IF_DHCP_OFFERED ||
ifctx->state == IF_DHCP_RESOLVED))) &&
(bootpc_tag(&gctx->tmptag, &ifctx->reply,
ifctx->replylen,
TAG_ROOT) != NULL ||
@ -459,7 +542,31 @@ bootpc_received(struct bootpc_globalcontext *gctx,
ifctx->replylen = gctx->replylen;
/* XXX: Only reset if 'perfect' response */
ifctx->state = IF_BOOTP_RESOLVED;
if (ifctx->state == IF_BOOTP_UNRESOLVED)
ifctx->state = IF_BOOTP_RESOLVED;
else if (ifctx->state == IF_DHCP_UNRESOLVED &&
ifctx->dhcpquerytype == DHCP_DISCOVER) {
if (dhcpreplytype == DHCP_OFFER)
ifctx->state = IF_DHCP_OFFERED;
else
ifctx->state = IF_BOOTP_RESOLVED; /* Fallback */
} else if (ifctx->state == IF_DHCP_OFFERED &&
ifctx->dhcpquerytype == DHCP_REQUEST)
ifctx->state = IF_DHCP_RESOLVED;
if (ifctx->dhcpquerytype == DHCP_DISCOVER &&
ifctx->state != IF_BOOTP_RESOLVED) {
p = bootpc_tag(&gctx->tmptag, &ifctx->reply,
ifctx->replylen, TAG_DHCP_SERVERID);
if (p != NULL && gctx->tmptag.taglen == 4) {
memcpy(&ifctx->dhcpserver, p, 4);
ifctx->gotdhcpserver = 1;
} else
ifctx->gotdhcpserver = 0;
return 1;
}
ifctx->gotrootpath = (bootpc_tag(&gctx->tmptag, &ifctx->reply,
ifctx->replylen,
TAG_ROOT) != NULL);
@ -488,6 +595,8 @@ bootpc_call(struct bootpc_globalcontext *gctx,
struct bootpc_ifcontext *ifctx;
int outstanding;
int gotrootpath;
int retry;
const char *s;
/*
* Create socket and set its recieve timeout.
@ -568,7 +677,7 @@ bootpc_call(struct bootpc_globalcontext *gctx,
for (ifctx = gctx->interfaces;
ifctx != NULL;
ifctx = ifctx->next) {
if (ifctx->state == IF_BOOTP_RESOLVED &&
if (bootpc_ifctx_isresolved(ifctx) != 0 &&
bootpc_tag(&gctx->tmptag, &ifctx->reply,
ifctx->replylen,
TAG_ROOT) != NULL)
@ -579,21 +688,45 @@ bootpc_call(struct bootpc_globalcontext *gctx,
ifctx != NULL;
ifctx = ifctx->next) {
ifctx->outstanding = 0;
if (ifctx->state == IF_BOOTP_RESOLVED &&
if (bootpc_ifctx_isresolved(ifctx) != 0 &&
gotrootpath != 0) {
continue;
}
if (ifctx->state == IF_BOOTP_FAILED)
if (bootpc_ifctx_isfailed(ifctx) != 0)
continue;
outstanding++;
ifctx->outstanding = 1;
/* Proceed to next step in DHCP negotiation */
if ((ifctx->state == IF_DHCP_OFFERED &&
ifctx->dhcpquerytype != DHCP_REQUEST) ||
(ifctx->state == IF_DHCP_UNRESOLVED &&
ifctx->dhcpquerytype != DHCP_DISCOVER) ||
(ifctx->state == IF_BOOTP_UNRESOLVED &&
ifctx->dhcpquerytype != DHCP_NOMSG)) {
ifctx->sentmsg = 0;
bootpc_compose_query(ifctx, gctx, procp);
}
/* Send BOOTP request (or re-send). */
if (ifctx->sentmsg == 0) {
printf("Sending BOOTP Query packet from "
switch(ifctx->dhcpquerytype) {
case DHCP_DISCOVER:
s = "DHCP Discover";
break;
case DHCP_REQUEST:
s = "DHCP Request";
break;
case DHCP_NOMSG:
default:
s = "BOOTP Query";
break;
}
printf("Sending %s packet from "
"interface %s (%*D)\n",
s,
ifctx->ireq.ifr_name,
ifctx->sdl->sdl_alen,
(unsigned char *) LLADDR(ifctx->sdl),
@ -657,7 +790,7 @@ bootpc_call(struct bootpc_globalcontext *gctx,
if (timo < MAX_RESEND_DELAY)
timo++;
else {
printf("BOOTP timeout for server ");
printf("DHCP/BOOTP timeout for server ");
print_sin_addr(&dst);
printf("\n");
}
@ -686,10 +819,10 @@ bootpc_call(struct bootpc_globalcontext *gctx,
for (ifctx = gctx->interfaces;
ifctx != NULL;
ifctx = ifctx->next) {
if (ifctx->state == IF_BOOTP_RESOLVED)
continue;
if (ifctx->state == IF_BOOTP_FAILED)
if (bootpc_ifctx_isresolved(ifctx) != 0 ||
bootpc_ifctx_isfailed(ifctx) != 0)
continue;
ifctx->call.secs = htons(gctx->secs);
}
if (error == EWOULDBLOCK)
@ -728,8 +861,28 @@ bootpc_call(struct bootpc_globalcontext *gctx,
}
if (ifctx != NULL) {
printf("Received BOOTP Reply packet"
s = bootpc_tag(&gctx->tmptag,
&gctx->reply,
gctx->replylen,
TAG_DHCP_MSGTYPE);
if (s != NULL) {
switch (*s) {
case DHCP_OFFER:
s = "DHCP Offer";
break;
case DHCP_ACK:
s = "DHCP Ack";
break;
default:
s = "DHCP (unexpected)";
break;
}
} else
s = "BOOTP Reply";
printf("Received %s packet"
" on %s from ",
s,
ifctx->ireq.ifr_name);
print_in_addr(gctx->reply.siaddr);
if (gctx->reply.giaddr.s_addr !=
@ -763,6 +916,21 @@ bootpc_call(struct bootpc_globalcontext *gctx,
if (gctx->secs > BOOTP_TIMEOUT && BOOTP_TIMEOUT > 0)
break;
#endif
/* Force a retry if halfway in DHCP negotiation */
retry = 0;
for (ifctx = gctx->interfaces; ifctx != NULL;
ifctx = ifctx->next) {
if (ifctx->state == IF_DHCP_OFFERED) {
if (ifctx->dhcpquerytype == DHCP_DISCOVER)
retry = 1;
else
ifctx->state = IF_DHCP_UNRESOLVED;
}
}
if (retry != 0)
continue;
if (gotrootpath != 0) {
gctx->gotrootpath = gotrootpath;
if (rtimo != 0 && time_second >= rtimo)
@ -776,8 +944,10 @@ bootpc_call(struct bootpc_globalcontext *gctx,
*/
for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) {
if (ifctx->state != IF_BOOTP_RESOLVED) {
printf("BOOTP timeout for interface %s\n",
if (bootpc_ifctx_isresolved(ifctx) == 0) {
printf("%s timeout for interface %s\n",
ifctx->dhcpquerytype != DHCP_NOMSG ?
"DHCP" : "BOOTP",
ifctx->ireq.ifr_name);
}
}
@ -790,7 +960,7 @@ bootpc_call(struct bootpc_globalcontext *gctx,
}
#ifndef BOOTP_NFSROOT
for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) {
if (ifctx->state == IF_BOOTP_RESOLVED) {
if (bootpc_ifctx_isresolved(ifctx) != 0) {
error = 0;
goto out;
}
@ -920,7 +1090,7 @@ bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
netmask = &ifctx->netmask;
gw = &ifctx->gw;
if (ifctx->state != IF_BOOTP_RESOLVED) {
if (bootpc_ifctx_isresolved(ifctx) == 0) {
/* Shutdown interfaces where BOOTP failed */
@ -1161,12 +1331,11 @@ bootpc_compose_query(ifctx, gctx, procp)
struct bootpc_globalcontext *gctx;
struct proc *procp;
{
gctx->gotrootpath = 0;
gctx->gotswappath = 0;
gctx->gotgw = 0;
unsigned char *vendp;
uint32_t leasetime;
ifctx->gotrootpath = 0;
bzero((caddr_t) &ifctx->call, sizeof(ifctx->call));
/* bootpc part */
@ -1174,19 +1343,53 @@ bootpc_compose_query(ifctx, gctx, procp)
ifctx->call.htype = 1; /* 10mb ethernet */
ifctx->call.hlen = ifctx->sdl->sdl_alen;/* Hardware address length */
ifctx->call.hops = 0;
ifctx->xid++;
if (bootpc_ifctx_isunresolved(ifctx) != 0)
ifctx->xid++;
ifctx->call.xid = txdr_unsigned(ifctx->xid);
bcopy(LLADDR(ifctx->sdl), &ifctx->call.chaddr, ifctx->sdl->sdl_alen);
ifctx->call.vend[0] = 99; /* RFC1048 cookie */
ifctx->call.vend[1] = 130;
ifctx->call.vend[2] = 83;
ifctx->call.vend[3] = 99;
ifctx->call.vend[4] = TAG_MAXMSGSIZE;
ifctx->call.vend[5] = 2;
ifctx->call.vend[6] = (sizeof(struct bootp_packet) >> 8) & 255;
ifctx->call.vend[7] = sizeof(struct bootp_packet) & 255;
ifctx->call.vend[8] = TAG_END;
vendp = ifctx->call.vend;
*vendp++ = 99; /* RFC1048 cookie */
*vendp++ = 130;
*vendp++ = 83;
*vendp++ = 99;
*vendp++ = TAG_MAXMSGSIZE;
*vendp++ = 2;
*vendp++ = (sizeof(struct bootp_packet) >> 8) & 255;
*vendp++ = sizeof(struct bootp_packet) & 255;
ifctx->dhcpquerytype = DHCP_NOMSG;
switch (ifctx->state) {
case IF_DHCP_UNRESOLVED:
*vendp++ = TAG_DHCP_MSGTYPE;
*vendp++ = 1;
*vendp++ = DHCP_DISCOVER;
ifctx->dhcpquerytype = DHCP_DISCOVER;
ifctx->gotdhcpserver = 0;
break;
case IF_DHCP_OFFERED:
*vendp++ = TAG_DHCP_MSGTYPE;
*vendp++ = 1;
*vendp++ = DHCP_REQUEST;
ifctx->dhcpquerytype = DHCP_REQUEST;
*vendp++ = TAG_DHCP_REQ_ADDR;
*vendp++ = 4;
memcpy(vendp, &ifctx->reply.yiaddr, 4);
vendp += 4;
if (ifctx->gotdhcpserver != 0) {
*vendp++ = TAG_DHCP_SERVERID;
*vendp++ = 4;
memcpy(vendp, &ifctx->dhcpserver, 4);
vendp += 4;
}
*vendp++ = TAG_DHCP_LEASETIME;
*vendp++ = 4;
leasetime = htonl(300);
memcpy(vendp, &leasetime, 4);
vendp += 4;
default:
;
}
*vendp = TAG_END;
ifctx->call.secs = 0;
ifctx->call.flags = htons(0x8000); /* We need an broadcast answer */
@ -1537,6 +1740,10 @@ bootpc_init(void)
#endif
}
gctx->gotrootpath = 0;
gctx->gotswappath = 0;
gctx->gotgw = 0;
for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
bootpc_fakeup_interface(ifctx, gctx, procp);
@ -1559,7 +1766,7 @@ bootpc_init(void)
mountopts(&nd->swap_args, NULL);
for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
if (ifctx->state == IF_BOOTP_RESOLVED)
if (bootpc_ifctx_isresolved(ifctx) != 0)
bootpc_decode_reply(nd, ifctx, gctx);
if (gctx->gotswappath == 0)
@ -1582,7 +1789,7 @@ bootpc_init(void)
for (ifctx = gctx->interfaces;
ifctx != NULL;
ifctx = ifctx->next)
if (ifctx->state == IF_BOOTP_RESOLVED)
if (bootpc_ifctx_isresolved(ifctx) != 0)
break;
}
if (ifctx == NULL)