proto_tftm.c revision d65680efa46fa49e8bf14e67b29b782510ff934c
/**************************************************************************
*
* proto_tftm.c -- Etherboot Multicast TFTP
* Written 2003-2003 by Timothy Legge <tlegge@rogers.com>
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* This code is based on the DOWNLOAD_PROTO_TFTM section of
/*
* Sun GPL Disclaimer: For the avoidance of doubt, except that if any license choice
* other than GPL or LGPL is available it will apply instead, Sun elects to use only
* the General Public License version 2 (GPLv2) at this time for any software where
* a choice of GPL license versions is made available with the language indicating
* that GPLv2 or any later version may be used, or where a choice of which version
* of the GPL is applied is otherwise unspecified.
*/
*
* Eric Biederman's proto_slam.c
*
* $Revision$
* $Author$
* $Date$
*
* ================
*
***************************************************************************/
#ifdef DOWNLOAD_PROTO_TFTM
#include "etherboot.h"
#include "nic.h"
//#define TFTM_DEBUG
#ifdef TFTM_DEBUG
#else
#define debug(x)
#endif
struct tftm_info {
int (*fnc) (unsigned char *, unsigned int, unsigned int, int);
int sent_nack;
const char *name; /* Filename */
};
struct tftm_state {
unsigned long block_size;
unsigned long total_bytes;
unsigned long total_packets;
char ismaster;
unsigned long received_packets;
unsigned char *image;
unsigned char *bitmap;
char recvd_oack;
} state;
#define TFTM_PORT 1758
#define TFTM_MIN_PACKET 1024
{
/* Check for Unicast data being received */
if (!udp) {
return 0;
}
return 0;
return 0;
return 1; /* Unicast Data Received */
}
/* Also check for Multicast data being received */
sizeof(struct udphdr))) {
return 1; /* Multicast data received */
}
return 0;
}
{
int retry = 0;
static unsigned short iport = 2000;
unsigned short oport = 0;
unsigned long filesize = 0;
rx_qdrain();
/* Warning: the following assumes the layout of bootp_t.
But that's fixed by the IP, UDP and BOOTP specs. */
/* Send a tftm-request to the server */
len =
"%s%coctet%cmulticast%c%cblksize%c%d%ctsize%c",
return (0);
/* loop to listen for packets and to receive the file */
for (;;) {
long timeout;
#ifdef CONGESTED
timeout =
retry);
#else
#endif
/* Calls the await_reply function in nic.c which in turn calls
await_tftm (1st parameter) as above */
if (!udp_transmit
return (0);
continue;
}
#ifdef CONGESTED
#ifdef MDEBUG
printf("<REXMT>\n");
#endif
debug(("Timed out receiving file"));
len =
"%s%coctet%cmulticast%c%cblksize%c%d%ctsize%c",
TFTM_MIN_PACKET, 0, 0) + 1;
continue;
}
#endif
break; /* timeout */
}
printf("TFTP error %d (%s)\n",
break;
}
int i =
/* Transmit an error message to the server to end the transmission */
("TFTM-Server doesn't understand options [blksize tsize multicast]\n");
/*
* Warning: the following assumes the layout of bootp_t.
* But that's fixed by the IP, UDP and BOOTP specs.
*/
len =
/*
* Normally bad form to omit the format string, but in this case
* the string we are copying from is fixed. sprintf is just being
* used as a strcpy and strlen.
*/
"RFC2090 error") + 1;
/* the packet does not get */
/* processed as data! */
return (0);
} else {
unsigned long bitmap_len;
/* */
if (!state.recvd_oack) {
1 + (filesize -
(filesize %
state.block_size)) /
if ((unsigned long) state.
("ALERT: tftp filesize to large for available memory\n");
return 0;
}
}
/* If I'm running over multicast join the multicast group */
s_addr);
}
}
unsigned long data_len;
unsigned char *data;
udp =
sizeof(struct
iphdr)];
len =
data =
sizeof(struct udphdr) + 4;
continue; /* ignore it */
printf("ALERT: Invalid packet number\n");
continue;
}
/* Compute the expected data length */
} else {
}
/* If the packet size is wrong drop the packet and then continue */
("ALERT: udp packet is not the correct size: %d\n",
block);
continue;
}
("ALERT: Ethernet packet shorter than data_len: %d\n",
block);
continue;
}
}
if (((state.
0) {
/* Non duplicate packet */
} else {
/* printf("<DUP>\n"); */
}
}
else { /* neither TFTP_OACK, TFTP_DATA nor TFTP_ERROR */
break;
}
unsigned long b;
unsigned long len;
unsigned long max;
int value;
int last;
/* Compute the last bit and store an inverted trailer */
value =
((state.
1) & 7)) & 1);
len = 0;
last = 0; /* Start with the received packets */
for (b = 1; b <= max; b++) {
value =
if (value == 0) {
break;
}
}
}
}
/* If the client is finished and not the master,
* ack the last packet */
/* Ack Last packet to end xfer */
}
/* We are done get out */
break;
}
/* Retransmission or OACK, don't process via callback
* and don't change the value of prevblock. */
continue;
}
retry = 0; /* It's the right place to zero the timer? */
}
/* Leave the multicast group */
}
int (*fnc) (unsigned char *, unsigned int, unsigned int, int))
{
int ret;
/* Set the defaults */
state.block_size = 0;
state.total_bytes = 0;
state.total_packets = 0;
state.received_packets = 0;
state.recvd_oack = 0;
if (name[0] != '/') {
/* server ip given, so use it */
/* No way to specify another port for now */
}
if (name[0] != '/') {
return 0;
}
return ret;
}
/******************************
* Parse the multicast options
*******************************/
{
int i = 0;
if (*len > TFTM_MIN_PACKET)
return -1;
e = p + *len;
while (*p != '\0' && p < e) {
if (!strcasecmp("tsize", p)) {
p += 6;
i |= 4;
debug(("\n"));
while (p < e && *p)
p++;
if (p < e)
p++;
} else if (!strcasecmp("blksize", p)) {
i |= 2;
p += 8;
("TFTM-Server rejected required transfer blocksize %d\n",
return 0;
}
while (p < e && *p)
p++;
if (p < e)
p++;
i |= 1;
p += 10;
debug(("multicast options: %s\n", p));
++p;
debug(("multicast port = %d\n",
info->multicast_port));
debug(("multicast ismaster = %d\n",
while (p < e && *p)
p++;
if (p < e)
p++;
}
}
if (p > e)
return 0;
return i;
}
#endif /* DOWNLOAD_PROTO_TFTM */