Some cleanup of BOOTP code. Initially I wanted to just change the ifioctl()

usage, but end up with more changes.

- Use SIOCAIFADDR instead of old rusty SIOCSIFADDR, SIOCSIFBRDADDR
  and SIOCSIFNETMASK.
- Use queue(9) instead of hand made stailq.
- Use one socket for all ifioctl() and send/receive operations.
- Use __func__ instead of cut-n-paste in logging and panics.
- Axe some dead or strange code.

Tested by:	gonzo, Stefan Bethke <stb lassitu.de>
This commit is contained in:
Gleb Smirnoff 2011-12-13 07:02:48 +00:00
parent 55174c34ef
commit 6bfaa83996
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=228455

View File

@ -64,6 +64,7 @@ __FBSDID("$FreeBSD$");
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <net/if_types.h>
#include <net/if_dl.h>
#include <net/vnet.h>
@ -109,19 +110,22 @@ struct bootp_packet {
};
struct bootpc_ifcontext {
struct bootpc_ifcontext *next;
STAILQ_ENTRY(bootpc_ifcontext) next;
struct bootp_packet call;
struct bootp_packet reply;
int replylen;
int overload;
struct socket *so;
struct ifreq ireq;
union {
struct ifreq _ifreq;
struct in_aliasreq _in_alias_req;
} _req;
#define ireq _req._ifreq
#define iareq _req._in_alias_req
struct ifnet *ifp;
struct sockaddr_dl *sdl;
struct sockaddr_in myaddr;
struct sockaddr_in netmask;
struct sockaddr_in gw;
struct sockaddr_in broadcast; /* Different for each interface */
int gotgw;
int gotnetmask;
int gotrootpath;
@ -153,8 +157,7 @@ struct bootpc_tagcontext {
};
struct bootpc_globalcontext {
struct bootpc_ifcontext *interfaces;
struct bootpc_ifcontext *lastinterface;
STAILQ_HEAD(, bootpc_ifcontext) interfaces;
u_int32_t xid;
int gotrootpath;
int gotgw;
@ -215,6 +218,7 @@ struct bootpc_globalcontext {
#endif
static char bootp_cookie[128];
static struct socket *bootp_so;
SYSCTL_STRING(_kern, OID_AUTO, bootp_cookie, CTLFLAG_RD,
bootp_cookie, 0, "Cookie (T134) supplied by bootp server");
@ -233,7 +237,7 @@ static void print_sin_addr(struct sockaddr_in *addr);
static void clear_sinaddr(struct sockaddr_in *sin);
static void allocifctx(struct bootpc_globalcontext *gctx);
static void bootpc_compose_query(struct bootpc_ifcontext *ifctx,
struct bootpc_globalcontext *gctx, struct thread *td);
struct thread *td);
static unsigned char *bootpc_tag(struct bootpc_tagcontext *tctx,
struct bootp_packet *bp, int len, int tag);
static void bootpc_tag_helper(struct bootpc_tagcontext *tctx,
@ -251,8 +255,8 @@ void bootpboot_p_iflist(void);
static int bootpc_call(struct bootpc_globalcontext *gctx,
struct thread *td);
static int bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx,
struct bootpc_globalcontext *gctx, struct thread *td);
static void bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx,
struct thread *td);
static int bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
struct bootpc_globalcontext *gctx, struct thread *td);
@ -270,14 +274,9 @@ static __inline int bootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx);
/*
* In order to have multiple active interfaces with address 0.0.0.0
* and be able to send data to a selected interface, we perform
* some tricks:
*
* - The 'broadcast' address is different for each interface.
*
* - We temporarily add routing pointing 255.255.255.255 to the
* selected interface broadcast address, thus the packet sent
* goes to that interface.
* and be able to send data to a selected interface, we first set
* mask to /8 on all interfaces, and temporarily set it to /0 when
* doing sosend().
*/
#ifdef BOOTP_DEBUG
@ -419,11 +418,8 @@ static void
allocifctx(struct bootpc_globalcontext *gctx)
{
struct bootpc_ifcontext *ifctx;
ifctx = (struct bootpc_ifcontext *) malloc(sizeof(*ifctx),
M_TEMP, M_WAITOK | M_ZERO);
if (ifctx == NULL)
panic("Failed to allocate bootp interface context structure");
ifctx = malloc(sizeof(*ifctx), M_TEMP, M_WAITOK | M_ZERO);
ifctx->xid = gctx->xid;
#ifdef BOOTP_NO_DHCP
ifctx->state = IF_BOOTP_UNRESOLVED;
@ -431,11 +427,7 @@ allocifctx(struct bootpc_globalcontext *gctx)
ifctx->state = IF_DHCP_UNRESOLVED;
#endif
gctx->xid += 0x100;
if (gctx->interfaces != NULL)
gctx->lastinterface->next = ifctx;
else
gctx->interfaces = ifctx;
gctx->lastinterface = ifctx;
STAILQ_INSERT_TAIL(&gctx->interfaces, ifctx, next);
}
static __inline int
@ -570,7 +562,6 @@ bootpc_received(struct bootpc_globalcontext *gctx,
static int
bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td)
{
struct socket *so;
struct sockaddr_in *sin, dst;
struct uio auio;
struct sockopt sopt;
@ -585,13 +576,6 @@ bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td)
int retry;
const char *s;
/*
* Create socket and set its recieve timeout.
*/
error = socreate(AF_INET, &so, SOCK_DGRAM, 0, td->td_ucred, td);
if (error != 0)
goto out0;
tv.tv_sec = 1;
tv.tv_usec = 0;
bzero(&sopt, sizeof(sopt));
@ -601,7 +585,7 @@ bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td)
sopt.sopt_val = &tv;
sopt.sopt_valsize = sizeof tv;
error = sosetopt(so, &sopt);
error = sosetopt(bootp_so, &sopt);
if (error != 0)
goto out;
@ -613,7 +597,7 @@ bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td)
sopt.sopt_val = &on;
sopt.sopt_valsize = sizeof on;
error = sosetopt(so, &sopt);
error = sosetopt(bootp_so, &sopt);
if (error != 0)
goto out;
@ -626,7 +610,7 @@ bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td)
sopt.sopt_val = &on;
sopt.sopt_valsize = sizeof on;
error = sosetopt(so, &sopt);
error = sosetopt(bootp_so, &sopt);
if (error != 0)
goto out;
@ -636,7 +620,7 @@ bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td)
sin = &dst;
clear_sinaddr(sin);
sin->sin_port = htons(IPPORT_BOOTPC);
error = sobind(so, (struct sockaddr *)sin, td);
error = sobind(bootp_so, (struct sockaddr *)sin, td);
if (error != 0) {
printf("bind failed\n");
goto out;
@ -662,9 +646,7 @@ bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td)
outstanding = 0;
gotrootpath = 0;
for (ifctx = gctx->interfaces;
ifctx != NULL;
ifctx = ifctx->next) {
STAILQ_FOREACH(ifctx, &gctx->interfaces, next) {
if (bootpc_ifctx_isresolved(ifctx) != 0 &&
bootpc_tag(&gctx->tmptag, &ifctx->reply,
ifctx->replylen,
@ -672,9 +654,10 @@ bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td)
gotrootpath = 1;
}
for (ifctx = gctx->interfaces;
ifctx != NULL;
ifctx = ifctx->next) {
STAILQ_FOREACH(ifctx, &gctx->interfaces, next) {
struct in_aliasreq *ifra = &ifctx->iareq;
sin = (struct sockaddr_in *)&ifra->ifra_mask;
ifctx->outstanding = 0;
if (bootpc_ifctx_isresolved(ifctx) != 0 &&
gotrootpath != 0) {
@ -694,7 +677,7 @@ bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td)
(ifctx->state == IF_BOOTP_UNRESOLVED &&
ifctx->dhcpquerytype != DHCP_NOMSG)) {
ifctx->sentmsg = 0;
bootpc_compose_query(ifctx, gctx, td);
bootpc_compose_query(ifctx, td);
}
/* Send BOOTP request (or re-send). */
@ -734,44 +717,32 @@ bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td)
auio.uio_td = td;
/* Set netmask to 0.0.0.0 */
sin = (struct sockaddr_in *) &ifctx->ireq.ifr_addr;
clear_sinaddr(sin);
error = ifioctl(ifctx->so, SIOCSIFNETMASK,
(caddr_t) &ifctx->ireq, td);
error = ifioctl(bootp_so, SIOCAIFADDR, (caddr_t)ifra,
td);
if (error != 0)
panic("bootpc_call:"
"set if netmask, error=%d",
error);
panic("%s: SIOCAIFADDR, error=%d", __func__,
error);
error = sosend(so, (struct sockaddr *) &dst,
error = sosend(bootp_so, (struct sockaddr *) &dst,
&auio, NULL, NULL, 0, td);
if (error != 0) {
printf("bootpc_call: sosend: %d state %08x\n",
error, (int) so->so_state);
}
/* XXX: Is this needed ? */
pause("bootpw", hz/10);
if (error != 0)
printf("%s: sosend: %d state %08x\n", __func__,
error, (int )bootp_so->so_state);
/* Set netmask to 255.0.0.0 */
sin = (struct sockaddr_in *) &ifctx->ireq.ifr_addr;
clear_sinaddr(sin);
sin->sin_addr.s_addr = htonl(0xff000000u);
error = ifioctl(ifctx->so, SIOCSIFNETMASK,
(caddr_t) &ifctx->ireq, td);
sin->sin_addr.s_addr = htonl(IN_CLASSA_NET);
error = ifioctl(bootp_so, SIOCAIFADDR, (caddr_t)ifra,
td);
if (error != 0)
panic("bootpc_call:"
"set if netmask, error=%d",
error);
panic("%s: SIOCAIFADDR, error=%d", __func__,
error);
}
if (outstanding == 0 &&
(rtimo == 0 || time_second >= rtimo)) {
error = 0;
goto gotreply;
goto out;
}
/* Determine new timeout. */
@ -801,12 +772,10 @@ bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td)
auio.uio_td = td;
rcvflg = 0;
error = soreceive(so, NULL, &auio,
error = soreceive(bootp_so, NULL, &auio,
NULL, NULL, &rcvflg);
gctx->secs = time_second - gctx->starttime;
for (ifctx = gctx->interfaces;
ifctx != NULL;
ifctx = ifctx->next) {
STAILQ_FOREACH(ifctx, &gctx->interfaces, next) {
if (bootpc_ifctx_isresolved(ifctx) != 0 ||
bootpc_ifctx_isfailed(ifctx) != 0)
continue;
@ -829,9 +798,7 @@ bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td)
continue;
/* Is this an answer to our query */
for (ifctx = gctx->interfaces;
ifctx != NULL;
ifctx = ifctx->next) {
STAILQ_FOREACH(ifctx, &gctx->interfaces, next) {
if (gctx->reply.xid != ifctx->call.xid)
continue;
@ -906,15 +873,13 @@ bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td)
#endif
/* Force a retry if halfway in DHCP negotiation */
retry = 0;
for (ifctx = gctx->interfaces; ifctx != NULL;
ifctx = ifctx->next) {
STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
if (ifctx->state == IF_DHCP_OFFERED) {
if (ifctx->dhcpquerytype == DHCP_DISCOVER)
retry = 1;
else
ifctx->state = IF_DHCP_UNRESOLVED;
}
}
if (retry != 0)
continue;
@ -931,14 +896,14 @@ bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td)
* ignored
*/
for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) {
STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
if (bootpc_ifctx_isresolved(ifctx) == 0) {
printf("%s timeout for interface %s\n",
ifctx->dhcpquerytype != DHCP_NOMSG ?
"DHCP" : "BOOTP",
ifctx->ireq.ifr_name);
}
}
if (gctx->gotrootpath != 0) {
#if 0
printf("Got a root path, ignoring remaining timeout\n");
@ -947,40 +912,28 @@ bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td)
goto out;
}
#ifndef BOOTP_NFSROOT
for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) {
STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
if (bootpc_ifctx_isresolved(ifctx) != 0) {
error = 0;
goto out;
}
}
#endif
error = ETIMEDOUT;
goto out;
gotreply:
out:
soclose(so);
out0:
return error;
return (error);
}
static int
bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx,
struct bootpc_globalcontext *gctx, struct thread *td)
static void
bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx, struct thread *td)
{
struct ifreq *ifr;
struct in_aliasreq *ifra;
struct sockaddr_in *sin;
int error;
struct ifreq *ireq;
struct socket *so;
struct ifaddr *ifa;
struct sockaddr_dl *sdl;
error = socreate(AF_INET, &ifctx->so, SOCK_DGRAM, 0, td->td_ucred, td);
if (error != 0)
panic("nfs_boot: socreate, error=%d", error);
ireq = &ifctx->ireq;
so = ifctx->so;
ifr = &ifctx->ireq;
ifra = &ifctx->iareq;
/*
* Bring up the interface.
@ -988,70 +941,56 @@ bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx,
* Get the old interface flags and or IFF_UP into them; if
* IFF_UP set blindly, interface selection can be clobbered.
*/
error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, td);
error = ifioctl(bootp_so, SIOCGIFFLAGS, (caddr_t)ifr, td);
if (error != 0)
panic("bootpc_fakeup_interface: GIFFLAGS, error=%d", error);
ireq->ifr_flags |= IFF_UP;
error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, td);
panic("%s: SIOCGIFFLAGS, error=%d", __func__, error);
ifr->ifr_flags |= IFF_UP;
error = ifioctl(bootp_so, SIOCSIFFLAGS, (caddr_t)ifr, td);
if (error != 0)
panic("bootpc_fakeup_interface: SIFFLAGS, error=%d", error);
panic("%s: SIOCSIFFLAGS, error=%d", __func__, error);
/*
* Do enough of ifconfig(8) so that the chosen interface
* can talk to the servers. (just set the address)
* can talk to the servers. Set address to 0.0.0.0/8 and
* broadcast address to local broadcast.
*/
/* addr is 0.0.0.0 */
sin = (struct sockaddr_in *) &ireq->ifr_addr;
sin = (struct sockaddr_in *)&ifra->ifra_addr;
clear_sinaddr(sin);
error = ifioctl(so, SIOCSIFADDR, (caddr_t) ireq, td);
if (error != 0 && (error != EEXIST || ifctx == gctx->interfaces))
panic("bootpc_fakeup_interface: "
"set if addr, error=%d", error);
/* netmask is 255.0.0.0 */
sin = (struct sockaddr_in *) &ireq->ifr_addr;
sin = (struct sockaddr_in *)&ifra->ifra_mask;
clear_sinaddr(sin);
sin->sin_addr.s_addr = htonl(0xff000000u);
error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, td);
if (error != 0)
panic("bootpc_fakeup_interface: set if netmask, error=%d",
error);
/* Broadcast is 255.255.255.255 */
sin = (struct sockaddr_in *)&ireq->ifr_addr;
sin->sin_addr.s_addr = htonl(IN_CLASSA_NET);
sin = (struct sockaddr_in *)&ifra->ifra_broadaddr;
clear_sinaddr(sin);
clear_sinaddr(&ifctx->broadcast);
sin->sin_addr.s_addr = htonl(INADDR_BROADCAST);
ifctx->broadcast.sin_addr.s_addr = sin->sin_addr.s_addr;
error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, td);
error = ifioctl(bootp_so, SIOCAIFADDR, (caddr_t)ifra, td);
if (error != 0)
panic("bootpc_fakeup_interface: "
"set if broadcast addr, error=%d",
error);
/* Get HW address */
sdl = NULL;
TAILQ_FOREACH(ifa, &ifctx->ifp->if_addrhead, ifa_link)
if (ifa->ifa_addr->sa_family == AF_LINK) {
sdl = (struct sockaddr_dl *)ifa->ifa_addr;
if (sdl->sdl_type == IFT_ETHER)
break;
}
if (sdl == NULL)
panic("bootpc: Unable to find HW address for %s",
ifctx->ireq.ifr_name);
ifctx->sdl = sdl;
return error;
panic("%s: SIOCAIFADDR, error=%d", __func__, error);
}
static void
bootpc_shutdown_interface(struct bootpc_ifcontext *ifctx, struct thread *td)
{
struct ifreq *ifr;
struct sockaddr_in *sin;
int error;
ifr = &ifctx->ireq;
printf("Shutdown interface %s\n", ifctx->ireq.ifr_name);
error = ifioctl(bootp_so, SIOCGIFFLAGS, (caddr_t)ifr, td);
if (error != 0)
panic("%s: SIOCGIFFLAGS, error=%d", __func__, error);
ifr->ifr_flags &= ~IFF_UP;
error = ifioctl(bootp_so, SIOCSIFFLAGS, (caddr_t)ifr, td);
if (error != 0)
panic("%s: SIOCSIFFLAGS, error=%d", __func__, error);
sin = (struct sockaddr_in *) &ifr->ifr_addr;
clear_sinaddr(sin);
error = ifioctl(bootp_so, SIOCDIFADDR, (caddr_t) ifr, td);
if (error != 0)
panic("%s: SIOCDIFADDR, error=%d", __func__, error);
}
static int
bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
@ -1061,42 +1000,22 @@ bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
struct sockaddr_in defdst;
struct sockaddr_in defmask;
struct sockaddr_in *sin;
struct ifreq *ireq;
struct socket *so;
struct ifreq *ifr;
struct in_aliasreq *ifra;
struct sockaddr_in *myaddr;
struct sockaddr_in *netmask;
struct sockaddr_in *gw;
ireq = &ifctx->ireq;
so = ifctx->so;
ifr = &ifctx->ireq;
ifra = &ifctx->iareq;
myaddr = &ifctx->myaddr;
netmask = &ifctx->netmask;
gw = &ifctx->gw;
if (bootpc_ifctx_isresolved(ifctx) == 0) {
/* Shutdown interfaces where BOOTP failed */
printf("Shutdown interface %s\n", ifctx->ireq.ifr_name);
error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, td);
if (error != 0)
panic("bootpc_adjust_interface: "
"SIOCGIFFLAGS, error=%d", error);
ireq->ifr_flags &= ~IFF_UP;
error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, td);
if (error != 0)
panic("bootpc_adjust_interface: "
"SIOCSIFFLAGS, error=%d", error);
sin = (struct sockaddr_in *) &ireq->ifr_addr;
clear_sinaddr(sin);
error = ifioctl(so, SIOCDIFADDR, (caddr_t) ireq, td);
if (error != 0 && (error != EEXIST ||
ifctx == gctx->interfaces))
panic("bootpc_adjust_interface: "
"SIOCDIFADDR, error=%d", error);
return 0;
bootpc_shutdown_interface(ifctx, td);
return (0);
}
printf("Adjusted interface %s\n", ifctx->ireq.ifr_name);
@ -1104,28 +1023,21 @@ bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
* Do enough of ifconfig(8) so that the chosen interface
* can talk to the servers. (just set the address)
*/
bcopy(netmask, &ireq->ifr_addr, sizeof(*netmask));
error = ifioctl(so, SIOCSIFNETMASK, (caddr_t) ireq, td);
if (error != 0)
panic("bootpc_adjust_interface: "
"set if netmask, error=%d", error);
/* Broadcast is with host part of IP address all 1's */
sin = (struct sockaddr_in *) &ireq->ifr_addr;
sin = (struct sockaddr_in *) &ifr->ifr_addr;
clear_sinaddr(sin);
sin->sin_addr.s_addr = myaddr->sin_addr.s_addr |
~ netmask->sin_addr.s_addr;
error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t) ireq, td);
error = ifioctl(bootp_so, SIOCDIFADDR, (caddr_t) ifr, td);
if (error != 0)
panic("bootpc_adjust_interface: "
"set if broadcast addr, error=%d", error);
panic("%s: SIOCDIFADDR, error=%d", __func__, error);
bcopy(myaddr, &ireq->ifr_addr, sizeof(*myaddr));
error = ifioctl(so, SIOCSIFADDR, (caddr_t) ireq, td);
if (error != 0 && (error != EEXIST || ifctx == gctx->interfaces))
panic("bootpc_adjust_interface: "
"set if addr, error=%d", error);
bcopy(myaddr, &ifra->ifra_addr, sizeof(*myaddr));
bcopy(netmask, &ifra->ifra_mask, sizeof(*netmask));
clear_sinaddr(&ifra->ifra_broadaddr);
ifra->ifra_broadaddr.sin_addr.s_addr = myaddr->sin_addr.s_addr |
~netmask->sin_addr.s_addr;
error = ifioctl(bootp_so, SIOCAIFADDR, (caddr_t)ifra, td);
if (error != 0)
panic("%s: SIOCAIFADDR, error=%d", __func__, error);
/* Add new default route */
@ -1139,13 +1051,12 @@ bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
(struct sockaddr *) &defmask,
(RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL, 0);
if (error != 0) {
printf("bootpc_adjust_interface: "
"add net route, error=%d\n", error);
return error;
printf("%s: RTM_ADD, error=%d\n", __func__, error);
return (error);
}
}
return 0;
return (0);
}
static int
@ -1288,8 +1199,7 @@ print_in_addr(struct in_addr addr)
}
static void
bootpc_compose_query(struct bootpc_ifcontext *ifctx,
struct bootpc_globalcontext *gctx, struct thread *td)
bootpc_compose_query(struct bootpc_ifcontext *ifctx, struct thread *td)
{
unsigned char *vendp;
unsigned char vendor_client[64];
@ -1595,9 +1505,11 @@ bootpc_decode_reply(struct nfsv3_diskless *nd, struct bootpc_ifcontext *ifctx,
void
bootpc_init(void)
{
struct bootpc_ifcontext *ifctx, *nctx; /* Interface BOOTP contexts */
struct bootpc_ifcontext *ifctx; /* Interface BOOTP contexts */
struct bootpc_globalcontext *gctx; /* Global BOOTP context */
struct ifnet *ifp;
struct sockaddr_dl *sdl;
struct ifaddr *ifa;
int error;
#ifndef BOOTP_WIRED_TO
int ifcnt;
@ -1615,9 +1527,7 @@ bootpc_init(void)
return;
gctx = malloc(sizeof(*gctx), M_TEMP, M_WAITOK | M_ZERO);
if (gctx == NULL)
panic("Failed to allocate bootp global context structure");
STAILQ_INIT(&gctx->interfaces);
gctx->xid = ~0xFFFF;
gctx->starttime = time_second;
@ -1626,7 +1536,7 @@ bootpc_init(void)
*/
CURVNET_SET(TD_TO_VNET(td));
#ifdef BOOTP_WIRED_TO
printf("bootpc_init: wired to interface '%s'\n",
printf("%s: wired to interface '%s'\n", __func__,
__XSTRING(BOOTP_WIRED_TO));
allocifctx(gctx);
#else
@ -1634,60 +1544,94 @@ bootpc_init(void)
* Preallocate interface context storage, if another interface
* attaches and wins the race, it won't be eligible for bootp.
*/
ifcnt = 0;
IFNET_RLOCK();
for (ifp = TAILQ_FIRST(&V_ifnet), ifcnt = 0;
ifp != NULL;
ifp = TAILQ_NEXT(ifp, if_link)) {
TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
if ((ifp->if_flags &
(IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) !=
IFF_BROADCAST)
continue;
switch (ifp->if_alloctype) {
case IFT_ETHER:
case IFT_FDDI:
case IFT_ISO88025:
break;
default:
continue;
}
ifcnt++;
}
IFNET_RUNLOCK();
if (ifcnt == 0)
panic("bootpc_init: no eligible interfaces");
panic("%s: no eligible interfaces", __func__);
for (; ifcnt > 0; ifcnt--)
allocifctx(gctx);
#endif
ifctx = STAILQ_FIRST(&gctx->interfaces);
IFNET_RLOCK();
for (ifp = TAILQ_FIRST(&V_ifnet), ifctx = gctx->interfaces;
ifp != NULL && ifctx != NULL;
ifp = TAILQ_NEXT(ifp, if_link)) {
strlcpy(ifctx->ireq.ifr_name, ifp->if_xname,
sizeof(ifctx->ireq.ifr_name));
TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
if (ifctx == NULL)
break;
#ifdef BOOTP_WIRED_TO
if (strcmp(ifctx->ireq.ifr_name,
__XSTRING(BOOTP_WIRED_TO)) != 0)
if (strcmp(ifp->if_xname, __XSTRING(BOOTP_WIRED_TO)) != 0)
continue;
#else
if ((ifp->if_flags &
(IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) !=
IFF_BROADCAST)
continue;
switch (ifp->if_alloctype) {
case IFT_ETHER:
case IFT_FDDI:
case IFT_ISO88025:
break;
default:
continue;
}
#endif
strlcpy(ifctx->ireq.ifr_name, ifp->if_xname,
sizeof(ifctx->ireq.ifr_name));
ifctx->ifp = ifp;
ifctx = ifctx->next;
/* Get HW address */
sdl = NULL;
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
if (ifa->ifa_addr->sa_family == AF_LINK) {
sdl = (struct sockaddr_dl *)ifa->ifa_addr;
if (sdl->sdl_type == IFT_ETHER)
break;
}
if (sdl == NULL)
panic("bootpc: Unable to find HW address for %s",
ifctx->ireq.ifr_name);
ifctx->sdl = sdl;
ifctx = STAILQ_NEXT(ifctx, next);
}
IFNET_RUNLOCK();
CURVNET_RESTORE();
if (gctx->interfaces == NULL || gctx->interfaces->ifp == NULL) {
if (STAILQ_EMPTY(&gctx->interfaces) ||
STAILQ_FIRST(&gctx->interfaces)->ifp == NULL) {
#ifdef BOOTP_WIRED_TO
panic("bootpc_init: Could not find interface specified "
panic("%s: Could not find interface specified "
"by BOOTP_WIRED_TO: "
__XSTRING(BOOTP_WIRED_TO));
__XSTRING(BOOTP_WIRED_TO), __func__);
#else
panic("bootpc_init: no suitable interface");
panic("%s: no suitable interface", __func__);
#endif
}
for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
bootpc_fakeup_interface(ifctx, gctx, td);
error = socreate(AF_INET, &bootp_so, SOCK_DGRAM, 0, td->td_ucred, td);
if (error != 0)
panic("%s: socreate, error=%d", __func__, error);
for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
bootpc_compose_query(ifctx, gctx, td);
STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
bootpc_fakeup_interface(ifctx, td);
STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
bootpc_compose_query(ifctx, td);
error = bootpc_call(gctx, td);
@ -1705,7 +1649,7 @@ bootpc_init(void)
#endif
mountopts(&nd->root_args, NULL);
for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
if (bootpc_ifctx_isresolved(ifctx) != 0)
bootpc_decode_reply(nd, ifctx, gctx);
@ -1714,19 +1658,16 @@ bootpc_init(void)
panic("bootpc: No root path offered");
#endif
for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) {
STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
bootpc_adjust_interface(ifctx, gctx, td);
soclose(ifctx->so);
}
soclose(bootp_so);
for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
if (ifctx->gotrootpath != 0)
break;
if (ifctx == NULL) {
for (ifctx = gctx->interfaces;
ifctx != NULL;
ifctx = ifctx->next)
STAILQ_FOREACH(ifctx, &gctx->interfaces, next)
if (bootpc_ifctx_isresolved(ifctx) != 0)
break;
}
@ -1755,8 +1696,8 @@ bootpc_init(void)
bcopy(&ifctx->netmask, &nd->myif.ifra_mask, sizeof(ifctx->netmask));
out:
for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = nctx) {
nctx = ifctx->next;
while((ifctx = STAILQ_FIRST(&gctx->interfaces)) != NULL) {
STAILQ_REMOVE_HEAD(&gctx->interfaces, next);
free(ifctx, M_TEMP);
}
free(gctx, M_TEMP);