diff options
Diffstat (limited to 'src/core/proto_tftm.c')
| -rw-r--r-- | src/core/proto_tftm.c | 491 |
1 files changed, 0 insertions, 491 deletions
diff --git a/src/core/proto_tftm.c b/src/core/proto_tftm.c deleted file mode 100644 index 8040fc445..000000000 --- a/src/core/proto_tftm.c +++ /dev/null @@ -1,491 +0,0 @@ -/************************************************************************** -* -* proto_tftm.c -- Etherboot Multicast TFTP -* Written 2003-2003 by Timothy Legge <tlegge@rogers.com> -* -* This program is free software; you can redistribute it and/or modify -* 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 -* Etherboot 5.3 core/nic.c and: -* -* Anselm Martin Hoffmeister's previous proto_tftm.c multicast work -* Eric Biederman's proto_slam.c -* -* $Revision$ -* $Author$ -* $Date$ -* -* REVISION HISTORY: -* ================ -* 09-07-2003 timlegge Release Version, Capable of Multicast Booting -* 08-30-2003 timlegge Initial version, Assumes consecutive blocks -* -* Indent Options: indent -kr -i8 -***************************************************************************/ - -#ifdef DOWNLOAD_PROTO_TFTM -#include "etherboot.h" -#include "nic.h" - -//#define TFTM_DEBUG -#ifdef TFTM_DEBUG -#define debug(x) printf x -#else -#define debug(x) -#endif -struct tftm_info { - in_addr server_ip; - in_addr multicast_ip; - in_addr local_ip; - uint16_t server_port; - uint16_t multicast_port; - uint16_t local_port; - 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 - - -int opt_get_multicast(struct tftp_t *tr, unsigned short *len, - unsigned long *filesize, struct tftm_info *info); - -static int await_tftm(int ival, void *ptr, unsigned short ptype __unused, - struct iphdr *ip, struct udphdr *udp) -{ - struct tftm_info *info = ptr; - - /* Check for Unicast data being received */ - if (ip->dest.s_addr == arptable[ARP_CLIENT].ipaddr.s_addr) { - if (!udp) { - return 0; - } - if (arptable[ARP_CLIENT].ipaddr.s_addr != ip->dest.s_addr) - return 0; - if (ntohs(udp->dest) != ival) - return 0; - - return 1; /* Unicast Data Received */ - } - - /* Also check for Multicast data being received */ - if ((ip->dest.s_addr == info->multicast_ip.s_addr) && - (ntohs(udp->dest) == info->multicast_port) && - (nic.packetlen >= ETH_HLEN + sizeof(struct iphdr) + - sizeof(struct udphdr))) { - return 1; /* Multicast data received */ - } - return 0; -} - -int proto_tftm(struct tftm_info *info) -{ - int retry = 0; - static unsigned short iport = 2000; - unsigned short oport = 0; - unsigned short len, block = 0, prevblock = 0; - struct tftp_t *tr; - struct tftpreq_t tp; - unsigned long filesize = 0; - - state.image = 0; - state.bitmap = 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 */ - tp.opcode = htons(TFTP_RRQ); /* Const for "\0x0" "\0x1" =^= ReadReQuest */ - len = - sizeof(tp.ip) + sizeof(tp.udp) + sizeof(tp.opcode) + - sprintf((char *) tp.u.rrq, - "%s%coctet%cmulticast%c%cblksize%c%d%ctsize%c", - info->name, 0, 0, 0, 0, 0, TFTM_MIN_PACKET, 0, 0) + 1; - - if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, ++iport, - TFTM_PORT, len, &tp)) - return (0); - - /* loop to listen for packets and to receive the file */ - for (;;) { - long timeout; -#ifdef CONGESTED - timeout = - rfc2131_sleep_interval(block ? TFTP_REXMT : TIMEOUT, - retry); -#else - timeout = rfc2131_sleep_interval(TIMEOUT, retry); -#endif - /* Calls the await_reply function in nic.c which in turn calls - await_tftm (1st parameter) as above */ - if (!await_reply(await_tftm, iport, info, timeout)) { - if (!block && retry++ < MAX_TFTP_RETRIES) { /* maybe initial request was lost */ - if (!udp_transmit - (arptable[ARP_SERVER].ipaddr.s_addr, - ++iport, TFTM_PORT, len, &tp)) - return (0); - continue; - } -#ifdef CONGESTED - if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT)) { /* we resend our last ack */ -#ifdef MDEBUG - printf("<REXMT>\n"); -#endif - debug(("Timed out receiving file")); - len = - sizeof(tp.ip) + sizeof(tp.udp) + - sizeof(tp.opcode) + - sprintf((char *) tp.u.rrq, - "%s%coctet%cmulticast%c%cblksize%c%d%ctsize%c", - info->name, 0, 0, 0, 0, 0, - TFTM_MIN_PACKET, 0, 0) + 1; - - udp_transmit - (arptable[ARP_SERVER].ipaddr.s_addr, - ++iport, TFTM_PORT, len, &tp); - continue; - } -#endif - break; /* timeout */ - } - - tr = (struct tftp_t *) &nic.packet[ETH_HLEN]; - - if (tr->opcode == ntohs(TFTP_ERROR)) { - printf("TFTP error %d (%s)\n", - ntohs(tr->u.err.errcode), tr->u.err.errmsg); - break; - } - - if (tr->opcode == ntohs(TFTP_OACK)) { - int i = - opt_get_multicast(tr, &len, &filesize, info); - - if (i == 0 || (i != 7 && !state.recvd_oack)) { /* Multicast unsupported */ - /* Transmit an error message to the server to end the transmission */ - printf - ("TFTM-Server doesn't understand options [blksize tsize multicast]\n"); - tp.opcode = htons(TFTP_ERROR); - tp.u.err.errcode = 8; - /* - * Warning: the following assumes the layout of bootp_t. - * But that's fixed by the IP, UDP and BOOTP specs. - */ - len = - sizeof(tp.ip) + sizeof(tp.udp) + - sizeof(tp.opcode) + - sizeof(tp.u.err.errcode) + - /* - * 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. - */ - sprintf((char *) tp.u.err.errmsg, - "RFC2090 error") + 1; - udp_transmit(arptable[ARP_SERVER].ipaddr. - s_addr, iport, - ntohs(tr->udp.src), len, &tp); - block = tp.u.ack.block = 0; /* this ensures, that */ - /* the packet does not get */ - /* processed as data! */ - return (0); - } else { - unsigned long bitmap_len; - /* */ - if (!state.recvd_oack) { - - state.total_packets = - 1 + (filesize - - (filesize % - state.block_size)) / - state.block_size; - bitmap_len = - (state.total_packets + 7) / 8; - if (!state.image) { - state.bitmap = - allot(bitmap_len); - state.image = - allot(filesize); - - if ((unsigned long) state. - image < 1024 * 1024) { - printf - ("ALERT: tftp filesize to large for available memory\n"); - return 0; - } - memset(state.bitmap, 0, - bitmap_len); - } - /* If I'm running over multicast join the multicast group */ - join_group(IGMP_SERVER, - info->multicast_ip. - s_addr); - } - state.recvd_oack = 1; - } - - - - } else if (tr->opcode == htons(TFTP_DATA)) { - unsigned long data_len; - unsigned char *data; - struct udphdr *udp; - udp = - (struct udphdr *) &nic.packet[ETH_HLEN + - sizeof(struct - iphdr)]; - len = - ntohs(tr->udp.len) - sizeof(struct udphdr) - 4; - data = - nic.packet + ETH_HLEN + sizeof(struct iphdr) + - sizeof(struct udphdr) + 4; - - if (len > TFTM_MIN_PACKET) /* shouldn't happen */ - continue; /* ignore it */ - - block = ntohs(tp.u.ack.block = tr->u.data.block); - - if (block > state.total_packets) { - printf("ALERT: Invalid packet number\n"); - continue; - } - - /* Compute the expected data length */ - if (block != state.total_packets) { - data_len = state.block_size; - } else { - data_len = filesize % state.block_size; - } - /* If the packet size is wrong drop the packet and then continue */ - if (ntohs(udp->len) != - (data_len + (data - (unsigned char *) udp))) { - printf - ("ALERT: udp packet is not the correct size: %d\n", - block); - continue; - } - if (nic.packetlen < data_len + (data - nic.packet)) { - printf - ("ALERT: Ethernet packet shorter than data_len: %d\n", - block); - continue; - } - - if (data_len > state.block_size) { - data_len = state.block_size; - } - if (((state. - bitmap[block >> 3] >> (block & 7)) & 1) == - 0) { - /* Non duplicate packet */ - state.bitmap[block >> 3] |= - (1 << (block & 7)); - memcpy(state.image + - ((block - 1) * state.block_size), - data, data_len); - state.received_packets++; - } else { - -/* printf("<DUP>\n"); */ - } - } - - else { /* neither TFTP_OACK, TFTP_DATA nor TFTP_ERROR */ - break; - } - - if (state.received_packets <= state.total_packets) { - unsigned long b; - unsigned long len; - unsigned long max; - int value; - int last; - - /* Compute the last bit and store an inverted trailer */ - max = state.total_packets + 1; - value = - ((state. - bitmap[(max - 1) >> 3] >> ((max - - 1) & 7)) & 1); - value = !value; - state.bitmap[max >> 3] &= ~(1 << (max & 7)); - state.bitmap[max >> 3] |= value << (max & 7); - - len = 0; - last = 0; /* Start with the received packets */ - for (b = 1; b <= max; b++) { - value = - (state.bitmap[b >> 3] >> (b & 7)) & 1; - - if (value == 0) { - tp.u.ack.block = htons(b - 1); /* Acknowledge the previous block */ - break; - } - } - } - if (state.ismaster) { - tp.opcode = htons(TFTP_ACK); - oport = ntohs(tr->udp.src); - udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, iport, oport, TFTP_MIN_PACKET, &tp); /* ack */ - } - if (state.received_packets == state.total_packets) { - /* If the client is finished and not the master, - * ack the last packet */ - if (!state.ismaster) { - tp.opcode = htons(TFTP_ACK); - /* Ack Last packet to end xfer */ - tp.u.ack.block = htons(state.total_packets); - oport = ntohs(tr->udp.src); - udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, iport, oport, TFTP_MIN_PACKET, &tp); /* ack */ - } - /* We are done get out */ - forget(state.bitmap); - break; - } - - if ((unsigned short) (block - prevblock) != 1) { - /* Retransmission or OACK, don't process via callback - * and don't change the value of prevblock. */ - continue; - } - - prevblock = block; - retry = 0; /* It's the right place to zero the timer? */ - - } - /* Leave the multicast group */ - leave_group(IGMP_SERVER); - return info->fnc(state.image, 1, filesize, 1); -} - -int url_tftm(const char *name, - int (*fnc) (unsigned char *, unsigned int, unsigned int, int)) -{ - - int ret; - struct tftm_info info; - - /* Set the defaults */ - info.server_ip.s_addr = arptable[ARP_SERVER].ipaddr.s_addr; - info.server_port = TFTM_PORT; - info.local_ip.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr; - info.local_port = TFTM_PORT; /* Does not matter. So take tftm port too. */ - info.multicast_ip.s_addr = info.local_ip.s_addr; - info.multicast_port = TFTM_PORT; - info.fnc = fnc; - state.ismaster = 0; - info.name = name; - - state.block_size = 0; - state.total_bytes = 0; - state.total_packets = 0; - state.received_packets = 0; - state.image = 0; - state.bitmap = 0; - state.recvd_oack = 0; - - if (name[0] != '/') { - /* server ip given, so use it */ - name += inet_aton(info.name, &info.server_ip); - /* No way to specify another port for now */ - } - if (name[0] != '/') { - printf("Bad tftm-URI: [%s]\n", info.name); - return 0; - } - - ret = proto_tftm(&info); - - return ret; -} - -/****************************** -* Parse the multicast options -*******************************/ -int opt_get_multicast(struct tftp_t *tr, unsigned short *len, - unsigned long *filesize, struct tftm_info *info) -{ - const char *p = tr->u.oack.data, *e = 0; - int i = 0; - *len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 2; - if (*len > TFTM_MIN_PACKET) - return -1; - e = p + *len; - - while (*p != '\0' && p < e) { - if (!strcasecmp("tsize", p)) { - p += 6; - if ((*filesize = strtoul(p, &p, 10)) > 0) - i |= 4; - debug(("\n")); - debug(("tsize=%d\n", *filesize)); - while (p < e && *p) - p++; - if (p < e) - p++; - } else if (!strcasecmp("blksize", p)) { - i |= 2; - p += 8; - state.block_size = strtoul(p, &p, 10); - if (state.block_size != TFTM_MIN_PACKET) { - printf - ("TFTM-Server rejected required transfer blocksize %d\n", - TFTM_MIN_PACKET); - return 0; - } - debug(("blksize=%d\n", state.block_size)); - while (p < e && *p) - p++; - if (p < e) - p++; - } else if (!strncmp(p, "multicast", 10)) { - i |= 1; - p += 10; - debug(("multicast options: %s\n", p)); - p += 1 + inet_aton(p, &info->multicast_ip); - debug(("multicast ip = %@\n", info->multicast_ip)); - info->multicast_port = strtoul(p, &p, 10); - ++p; - debug(("multicast port = %d\n", - info->multicast_port)); - state.ismaster = (*p == '1' ? 1 : 0); - debug(("multicast ismaster = %d\n", - state.ismaster)); - while (p < e && *p) - p++; - if (p < e) - p++; - } - } - if (p > e) - return 0; - return i; -} -#endif /* DOWNLOAD_PROTO_TFTP */ |
