/*-
* Copyright (c) 2000, 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Tohru Nishimura.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
#define WAITING 0 /* implicit state after receiving the first frame */
#define OPENING 1 /* waiting for OPEN after CONNECT is received */
#define TRANSFER 2 /* data transferring state after OPEN is well done */
static __unused const char *state[] = { "WAITING", "OPENING", "TRANSFER" };
/* ignore own TX packets */
if (memcmp(fp->src, station.addr, ETHER_ADDR_LEN) == 0)
continue;
/* check if the received Ethernet address is in ethers(5) */
if (ether_ntohost(clientname, (struct ether_addr *)fp->src)) {
TRACE(3, ("'%s' is not in ethers(5)\n",
etheraddr(fp->src)));
continue;
}
/* check if the client has a valid hostname */
clientname[sizeof(clientname) - 1] = '\0';
clientent = gethostbyname(clientname);
if (clientent == NULL || clientent->h_addrtype != AF_INET) {
TRACE(3, ("'%s' is not a valid host\n", clientname));
continue;
}
cp = search(fp->src);
TRACE(2, ("[%s] ", etheraddr(fp->src)));
switch (cp->state) {
case WAITING:
if (fp->opcode != CONNECT) {
TRACE(2, ("not connected\n"));
continue;
}
/* check if specified servername is mine */
fp->data[sizeof(fp->data) - 1] = '\0';
servername = (char *)fp->data;
if (strcmp(servername, station.name) != 0) {
TRACE(3, ("'%s' not for me\n", servername));
continue;
}
cp->state = OPENING;
TRACE(2, ("new connection\n"));
break;
case OPENING:
if (fp->opcode != OPEN)
goto aborting; /* out of phase */
/* don't allow files outside the specified dir */
fp->data[sizeof(fp->data) - 1] = '\0';
filename = strrchr((char *)fp->data, '/');
if (filename != NULL)
filename++;
else
filename = (char *)fp->data;
cp->file = fopen(filename, "r");
if (cp->file == NULL) {
TRACE(1, ("failed to open '%s'\n", filename));
goto closedown; /* no such file */
}
cp->state = TRANSFER;
TRACE(2, ("open '%s'\n", filename));
break;
case TRANSFER:
if (fp->opcode == CLOSE) {
TRACE(2, ("connection closed\n"));
goto closedown; /* close request */
}
if (fp->opcode != READ)
goto aborting; /* out of phase */
siz = be32dec(fp->siz);
pos = be32dec(fp->pos);
nread = siz;
if (nread > sizeof(fp->data) ||
fseek(cp->file, pos, 0L) < 0 ||
fread(fp->data, 1, nread, cp->file) < nread) {
be32enc(fp->siz, 0); /* corrupted file */
}
TRACE(3, ("%u@%u\n", siz, pos));
break;
aborting:
TRACE(1, ("out of phase\n"));
closedown:
closedown(cp);
fp->opcode = CLOSE;
break;
}
memcpy(fp->dst, fp->src, ETHER_ADDR_LEN);
memcpy(fp->src, station.addr, ETHER_ADDR_LEN);
write(pollfd.fd, fp, ISIBOOT_FRAMELEN);
}
/* NOTREACHED */
}