From 85d9eae44ef5e2c48fcbefe36fb7bdfcb54c9f75 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 1 May 2005 14:04:11 +0000 Subject: Moved protocols to proto/ --- src/core/nfs.c | 610 -------------------------------------------------- src/core/proto_http.c | 206 ----------------- src/core/proto_slam.c | 541 -------------------------------------------- src/core/proto_tftm.c | 491 ---------------------------------------- 4 files changed, 1848 deletions(-) delete mode 100644 src/core/nfs.c delete mode 100644 src/core/proto_http.c delete mode 100644 src/core/proto_slam.c delete mode 100644 src/core/proto_tftm.c (limited to 'src/core') diff --git a/src/core/nfs.c b/src/core/nfs.c deleted file mode 100644 index cbda6ab7b..000000000 --- a/src/core/nfs.c +++ /dev/null @@ -1,610 +0,0 @@ -#ifdef DOWNLOAD_PROTO_NFS - -#include "etherboot.h" -#include "nic.h" - -/* NOTE: the NFS code is heavily inspired by the NetBSD netboot code (read: - * large portions are copied verbatim) as distributed in OSKit 0.97. A few - * changes were necessary to adapt the code to Etherboot and to fix several - * inconsistencies. Also the RPC message preparation is done "by hand" to - * avoid adding netsprintf() which I find hard to understand and use. */ - -/* NOTE 2: Etherboot does not care about things beyond the kernel image, so - * it loads the kernel image off the boot server (ARP_SERVER) and does not - * access the client root disk (root-path in dhcpd.conf), which would use - * ARP_ROOTSERVER. The root disk is something the operating system we are - * about to load needs to use. This is different from the OSKit 0.97 logic. */ - -/* NOTE 3: Symlink handling introduced by Anselm M Hoffmeister, 2003-July-14 - * If a symlink is encountered, it is followed as far as possible (recursion - * possible, maximum 16 steps). There is no clearing of ".."'s inside the - * path, so please DON'T DO THAT. thx. */ - -#define START_OPORT 700 /* mountd usually insists on secure ports */ -#define OPORT_SWEEP 200 /* make sure we don't leave secure range */ - -static int oport = START_OPORT; -static int mount_port = -1; -static int nfs_port = -1; -static int fs_mounted = 0; -static unsigned long rpc_id; - -/************************************************************************** -RPC_INIT - set up the ID counter to something fairly random -**************************************************************************/ -void rpc_init(void) -{ - unsigned long t; - - t = currticks(); - rpc_id = t ^ (t << 8) ^ (t << 16); -} - - -/************************************************************************** -RPC_PRINTERROR - Print a low level RPC error message -**************************************************************************/ -static void rpc_printerror(struct rpc_t *rpc) -{ - if (rpc->u.reply.rstatus || rpc->u.reply.verifier || - rpc->u.reply.astatus) { - /* rpc_printerror() is called for any RPC related error, - * suppress output if no low level RPC error happened. */ - printf("RPC error: (%d,%d,%d)\n", ntohl(rpc->u.reply.rstatus), - ntohl(rpc->u.reply.verifier), - ntohl(rpc->u.reply.astatus)); - } -} - -/************************************************************************** -AWAIT_RPC - Wait for an rpc packet -**************************************************************************/ -static int await_rpc(int ival, void *ptr, - unsigned short ptype, struct iphdr *ip, struct udphdr *udp) -{ - struct rpc_t *rpc; - if (!udp) - return 0; - if (arptable[ARP_CLIENT].ipaddr.s_addr != ip->dest.s_addr) - return 0; - if (ntohs(udp->dest) != ival) - return 0; - if (nic.packetlen < ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr) + 8) - return 0; - rpc = (struct rpc_t *)&nic.packet[ETH_HLEN]; - if (*(unsigned long *)ptr != ntohl(rpc->u.reply.id)) - return 0; - if (MSG_REPLY != ntohl(rpc->u.reply.type)) - return 0; - return 1; -} - -/************************************************************************** -RPC_LOOKUP - Lookup RPC Port numbers -**************************************************************************/ -static int rpc_lookup(int addr, int prog, int ver, int sport) -{ - struct rpc_t buf, *rpc; - unsigned long id; - int retries; - long *p; - - id = rpc_id++; - buf.u.call.id = htonl(id); - buf.u.call.type = htonl(MSG_CALL); - buf.u.call.rpcvers = htonl(2); /* use RPC version 2 */ - buf.u.call.prog = htonl(PROG_PORTMAP); - buf.u.call.vers = htonl(2); /* portmapper is version 2 */ - buf.u.call.proc = htonl(PORTMAP_GETPORT); - p = (long *)buf.u.call.data; - *p++ = 0; *p++ = 0; /* auth credential */ - *p++ = 0; *p++ = 0; /* auth verifier */ - *p++ = htonl(prog); - *p++ = htonl(ver); - *p++ = htonl(IP_UDP); - *p++ = 0; - for (retries = 0; retries < MAX_RPC_RETRIES; retries++) { - long timeout; - udp_transmit(arptable[addr].ipaddr.s_addr, sport, SUNRPC_PORT, - (char *)p - (char *)&buf, &buf); - timeout = rfc2131_sleep_interval(TIMEOUT, retries); - if (await_reply(await_rpc, sport, &id, timeout)) { - rpc = (struct rpc_t *)&nic.packet[ETH_HLEN]; - if (rpc->u.reply.rstatus || rpc->u.reply.verifier || - rpc->u.reply.astatus) { - rpc_printerror(rpc); - return -1; - } else { - return ntohl(rpc->u.reply.data[0]); - } - } - } - return -1; -} - -/************************************************************************** -RPC_ADD_CREDENTIALS - Add RPC authentication/verifier entries -**************************************************************************/ -static long *rpc_add_credentials(long *p) -{ - int hl; - - /* Here's the executive summary on authentication requirements of the - * various NFS server implementations: Linux accepts both AUTH_NONE - * and AUTH_UNIX authentication (also accepts an empty hostname field - * in the AUTH_UNIX scheme). *BSD refuses AUTH_NONE, but accepts - * AUTH_UNIX (also accepts an empty hostname field in the AUTH_UNIX - * scheme). To be safe, use AUTH_UNIX and pass the hostname if we have - * it (if the BOOTP/DHCP reply didn't give one, just use an empty - * hostname). */ - - hl = (hostnamelen + 3) & ~3; - - /* Provide an AUTH_UNIX credential. */ - *p++ = htonl(1); /* AUTH_UNIX */ - *p++ = htonl(hl+20); /* auth length */ - *p++ = htonl(0); /* stamp */ - *p++ = htonl(hostnamelen); /* hostname string */ - if (hostnamelen & 3) { - *(p + hostnamelen / 4) = 0; /* add zero padding */ - } - memcpy(p, hostname, hostnamelen); - p += hl / 4; - *p++ = 0; /* uid */ - *p++ = 0; /* gid */ - *p++ = 0; /* auxiliary gid list */ - - /* Provide an AUTH_NONE verifier. */ - *p++ = 0; /* AUTH_NONE */ - *p++ = 0; /* auth length */ - - return p; -} - -/************************************************************************** -NFS_PRINTERROR - Print a NFS error message -**************************************************************************/ -static void nfs_printerror(int err) -{ - switch (-err) { - case NFSERR_PERM: - printf("Not owner\n"); - break; - case NFSERR_NOENT: - printf("No such file or directory\n"); - break; - case NFSERR_ACCES: - printf("Permission denied\n"); - break; - case NFSERR_ISDIR: - printf("Directory given where filename expected\n"); - break; - case NFSERR_INVAL: - printf("Invalid filehandle\n"); - break; // INVAL is not defined in NFSv2, some NFS-servers - // seem to use it in answers to v2 nevertheless. - case 9998: - printf("low-level RPC failure (parameter decoding problem?)\n"); - break; - case 9999: - printf("low-level RPC failure (authentication problem?)\n"); - break; - default: - printf("Unknown NFS error %d\n", -err); - } -} - -/************************************************************************** -NFS_MOUNT - Mount an NFS Filesystem -**************************************************************************/ -static int nfs_mount(int server, int port, char *path, char *fh, int sport) -{ - struct rpc_t buf, *rpc; - unsigned long id; - int retries; - long *p; - int pathlen = strlen(path); - - id = rpc_id++; - buf.u.call.id = htonl(id); - buf.u.call.type = htonl(MSG_CALL); - buf.u.call.rpcvers = htonl(2); /* use RPC version 2 */ - buf.u.call.prog = htonl(PROG_MOUNT); - buf.u.call.vers = htonl(1); /* mountd is version 1 */ - buf.u.call.proc = htonl(MOUNT_ADDENTRY); - p = rpc_add_credentials((long *)buf.u.call.data); - *p++ = htonl(pathlen); - if (pathlen & 3) { - *(p + pathlen / 4) = 0; /* add zero padding */ - } - memcpy(p, path, pathlen); - p += (pathlen + 3) / 4; - for (retries = 0; retries < MAX_RPC_RETRIES; retries++) { - long timeout; - udp_transmit(arptable[server].ipaddr.s_addr, sport, port, - (char *)p - (char *)&buf, &buf); - timeout = rfc2131_sleep_interval(TIMEOUT, retries); - if (await_reply(await_rpc, sport, &id, timeout)) { - rpc = (struct rpc_t *)&nic.packet[ETH_HLEN]; - if (rpc->u.reply.rstatus || rpc->u.reply.verifier || - rpc->u.reply.astatus || rpc->u.reply.data[0]) { - rpc_printerror(rpc); - if (rpc->u.reply.rstatus) { - /* RPC failed, no verifier, data[0] */ - return -9999; - } - if (rpc->u.reply.astatus) { - /* RPC couldn't decode parameters */ - return -9998; - } - return -ntohl(rpc->u.reply.data[0]); - } else { - fs_mounted = 1; - memcpy(fh, rpc->u.reply.data + 1, NFS_FHSIZE); - return 0; - } - } - } - return -1; -} - -/************************************************************************** -NFS_UMOUNTALL - Unmount all our NFS Filesystems on the Server -**************************************************************************/ -void nfs_umountall(int server) -{ - struct rpc_t buf, *rpc; - unsigned long id; - int retries; - long *p; - - if (!arptable[server].ipaddr.s_addr) { - /* Haven't sent a single UDP packet to this server */ - return; - } - if ((mount_port == -1) || (!fs_mounted)) { - /* Nothing mounted, nothing to umount */ - return; - } - id = rpc_id++; - buf.u.call.id = htonl(id); - buf.u.call.type = htonl(MSG_CALL); - buf.u.call.rpcvers = htonl(2); /* use RPC version 2 */ - buf.u.call.prog = htonl(PROG_MOUNT); - buf.u.call.vers = htonl(1); /* mountd is version 1 */ - buf.u.call.proc = htonl(MOUNT_UMOUNTALL); - p = rpc_add_credentials((long *)buf.u.call.data); - for (retries = 0; retries < MAX_RPC_RETRIES; retries++) { - long timeout = rfc2131_sleep_interval(TIMEOUT, retries); - udp_transmit(arptable[server].ipaddr.s_addr, oport, mount_port, - (char *)p - (char *)&buf, &buf); - if (await_reply(await_rpc, oport, &id, timeout)) { - rpc = (struct rpc_t *)&nic.packet[ETH_HLEN]; - if (rpc->u.reply.rstatus || rpc->u.reply.verifier || - rpc->u.reply.astatus) { - rpc_printerror(rpc); - } - fs_mounted = 0; - return; - } - } -} -/*************************************************************************** - * NFS_READLINK (AH 2003-07-14) - * This procedure is called when read of the first block fails - - * this probably happens when it's a directory or a symlink - * In case of successful readlink(), the dirname is manipulated, - * so that inside the nfs() function a recursion can be done. - **************************************************************************/ -static int nfs_readlink(int server, int port, char *fh, char *path, char *nfh, - int sport) -{ - struct rpc_t buf, *rpc; - unsigned long id; - long *p; - int retries; - int pathlen = strlen(path); - - id = rpc_id++; - buf.u.call.id = htonl(id); - buf.u.call.type = htonl(MSG_CALL); - buf.u.call.rpcvers = htonl(2); /* use RPC version 2 */ - buf.u.call.prog = htonl(PROG_NFS); - buf.u.call.vers = htonl(2); /* nfsd is version 2 */ - buf.u.call.proc = htonl(NFS_READLINK); - p = rpc_add_credentials((long *)buf.u.call.data); - memcpy(p, nfh, NFS_FHSIZE); - p += (NFS_FHSIZE / 4); - for (retries = 0; retries < MAX_RPC_RETRIES; retries++) { - long timeout = rfc2131_sleep_interval(TIMEOUT, retries); - udp_transmit(arptable[server].ipaddr.s_addr, sport, port, - (char *)p - (char *)&buf, &buf); - if (await_reply(await_rpc, sport, &id, timeout)) { - rpc = (struct rpc_t *)&nic.packet[ETH_HLEN]; - if (rpc->u.reply.rstatus || rpc->u.reply.verifier || - rpc->u.reply.astatus || rpc->u.reply.data[0]) { - rpc_printerror(rpc); - if (rpc->u.reply.rstatus) { - /* RPC failed, no verifier, data[0] */ - return -9999; - } - if (rpc->u.reply.astatus) { - /* RPC couldn't decode parameters */ - return -9998; - } - return -ntohl(rpc->u.reply.data[0]); - } else { - // It *is* a link. - // If it's a relative link, append everything to dirname, filename TOO! - retries = strlen ( (char *)(&(rpc->u.reply.data[2]) )); - if ( *((char *)(&(rpc->u.reply.data[2]))) != '/' ) { - path[pathlen++] = '/'; - while ( ( retries + pathlen ) > 298 ) { - retries--; - } - if ( retries > 0 ) { - memcpy(path + pathlen, &(rpc->u.reply.data[2]), retries + 1); - } else { retries = 0; } - path[pathlen + retries] = 0; - } else { - // Else make it the only path. - if ( retries > 298 ) { retries = 298; } - memcpy ( path, &(rpc->u.reply.data[2]), retries + 1 ); - path[retries] = 0; - } - return 0; - } - } - } - return -1; -} -/************************************************************************** -NFS_LOOKUP - Lookup Pathname -**************************************************************************/ -static int nfs_lookup(int server, int port, char *fh, char *path, char *nfh, - int sport) -{ - struct rpc_t buf, *rpc; - unsigned long id; - long *p; - int retries; - int pathlen = strlen(path); - - id = rpc_id++; - buf.u.call.id = htonl(id); - buf.u.call.type = htonl(MSG_CALL); - buf.u.call.rpcvers = htonl(2); /* use RPC version 2 */ - buf.u.call.prog = htonl(PROG_NFS); - buf.u.call.vers = htonl(2); /* nfsd is version 2 */ - buf.u.call.proc = htonl(NFS_LOOKUP); - p = rpc_add_credentials((long *)buf.u.call.data); - memcpy(p, fh, NFS_FHSIZE); - p += (NFS_FHSIZE / 4); - *p++ = htonl(pathlen); - if (pathlen & 3) { - *(p + pathlen / 4) = 0; /* add zero padding */ - } - memcpy(p, path, pathlen); - p += (pathlen + 3) / 4; - for (retries = 0; retries < MAX_RPC_RETRIES; retries++) { - long timeout = rfc2131_sleep_interval(TIMEOUT, retries); - udp_transmit(arptable[server].ipaddr.s_addr, sport, port, - (char *)p - (char *)&buf, &buf); - if (await_reply(await_rpc, sport, &id, timeout)) { - rpc = (struct rpc_t *)&nic.packet[ETH_HLEN]; - if (rpc->u.reply.rstatus || rpc->u.reply.verifier || - rpc->u.reply.astatus || rpc->u.reply.data[0]) { - rpc_printerror(rpc); - if (rpc->u.reply.rstatus) { - /* RPC failed, no verifier, data[0] */ - return -9999; - } - if (rpc->u.reply.astatus) { - /* RPC couldn't decode parameters */ - return -9998; - } - return -ntohl(rpc->u.reply.data[0]); - } else { - memcpy(nfh, rpc->u.reply.data + 1, NFS_FHSIZE); - return 0; - } - } - } - return -1; -} - -/************************************************************************** -NFS_READ - Read File on NFS Server -**************************************************************************/ -static int nfs_read(int server, int port, char *fh, int offset, int len, - int sport) -{ - struct rpc_t buf, *rpc; - unsigned long id; - int retries; - long *p; - - static int tokens=0; - /* - * Try to implement something similar to a window protocol in - * terms of response to losses. On successful receive, increment - * the number of tokens by 1 (cap at 256). On failure, halve it. - * When the number of tokens is >= 2, use a very short timeout. - */ - - id = rpc_id++; - buf.u.call.id = htonl(id); - buf.u.call.type = htonl(MSG_CALL); - buf.u.call.rpcvers = htonl(2); /* use RPC version 2 */ - buf.u.call.prog = htonl(PROG_NFS); - buf.u.call.vers = htonl(2); /* nfsd is version 2 */ - buf.u.call.proc = htonl(NFS_READ); - p = rpc_add_credentials((long *)buf.u.call.data); - memcpy(p, fh, NFS_FHSIZE); - p += NFS_FHSIZE / 4; - *p++ = htonl(offset); - *p++ = htonl(len); - *p++ = 0; /* unused parameter */ - for (retries = 0; retries < MAX_RPC_RETRIES; retries++) { - long timeout = rfc2131_sleep_interval(TIMEOUT, retries); - if (tokens >= 2) - timeout = TICKS_PER_SEC/2; - - udp_transmit(arptable[server].ipaddr.s_addr, sport, port, - (char *)p - (char *)&buf, &buf); - if (await_reply(await_rpc, sport, &id, timeout)) { - if (tokens < 256) - tokens++; - rpc = (struct rpc_t *)&nic.packet[ETH_HLEN]; - if (rpc->u.reply.rstatus || rpc->u.reply.verifier || - rpc->u.reply.astatus || rpc->u.reply.data[0]) { - rpc_printerror(rpc); - if (rpc->u.reply.rstatus) { - /* RPC failed, no verifier, data[0] */ - return -9999; - } - if (rpc->u.reply.astatus) { - /* RPC couldn't decode parameters */ - return -9998; - } - return -ntohl(rpc->u.reply.data[0]); - } else { - return 0; - } - } else - tokens >>= 1; - } - return -1; -} - -/************************************************************************** -NFS - Download extended BOOTP data, or kernel image from NFS server -**************************************************************************/ -int nfs(const char *name, int (*fnc)(unsigned char *, unsigned int, unsigned int, int)) -{ - static int recursion = 0; - int sport; - int err, namelen = strlen(name); - char dirname[300], *fname; - char dirfh[NFS_FHSIZE]; /* file handle of directory */ - char filefh[NFS_FHSIZE]; /* file handle of kernel image */ - unsigned int block; - int rlen, size, offs, len; - struct rpc_t *rpc; - - rx_qdrain(); - - sport = oport++; - if (oport > START_OPORT+OPORT_SWEEP) { - oport = START_OPORT; - } - if ( name != dirname ) { - memcpy(dirname, name, namelen + 1); - } - recursion = 0; -nfssymlink: - if ( recursion > NFS_MAXLINKDEPTH ) { - printf ( "\nRecursion: More than %d symlinks followed. Abort.\n", NFS_MAXLINKDEPTH ); - return 0; - } - recursion++; - fname = dirname + (namelen - 1); - while (fname >= dirname) { - if (*fname == '/') { - *fname = '\0'; - fname++; - break; - } - fname--; - } - if (fname < dirname) { - printf("can't parse file name %s\n", name); - return 0; - } - - if (mount_port == -1) { - mount_port = rpc_lookup(ARP_SERVER, PROG_MOUNT, 1, sport); - } - if (nfs_port == -1) { - nfs_port = rpc_lookup(ARP_SERVER, PROG_NFS, 2, sport); - } - if (nfs_port == -1 || mount_port == -1) { - printf("can't get nfs/mount ports from portmapper\n"); - return 0; - } - - - err = nfs_mount(ARP_SERVER, mount_port, dirname, dirfh, sport); - if (err) { - printf("mounting %s: ", dirname); - nfs_printerror(err); - /* just to be sure... */ - nfs_umountall(ARP_SERVER); - return 0; - } - - err = nfs_lookup(ARP_SERVER, nfs_port, dirfh, fname, filefh, sport); - if (err) { - printf("looking up %s: ", fname); - nfs_printerror(err); - nfs_umountall(ARP_SERVER); - return 0; - } - - offs = 0; - block = 1; /* blocks are numbered starting from 1 */ - size = -1; /* will be set properly with the first reply */ - len = NFS_READ_SIZE; /* first request is always full size */ - do { - err = nfs_read(ARP_SERVER, nfs_port, filefh, offs, len, sport); - if ((err <= -NFSERR_ISDIR)&&(err >= -NFSERR_INVAL) && (offs == 0)) { - // An error occured. NFS servers tend to sending - // errors 21 / 22 when symlink instead of real file - // is requested. So check if it's a symlink! - block = nfs_readlink(ARP_SERVER, nfs_port, dirfh, dirname, - filefh, sport); - if ( 0 == block ) { - printf("\nLoading symlink:%s ..",dirname); - goto nfssymlink; - } - nfs_printerror(err); - nfs_umountall(ARP_SERVER); - return 0; - } - if (err) { - printf("reading at offset %d: ", offs); - nfs_printerror(err); - nfs_umountall(ARP_SERVER); - return 0; - } - - rpc = (struct rpc_t *)&nic.packet[ETH_HLEN]; - - /* size must be found out early to allow EOF detection */ - if (size == -1) { - size = ntohl(rpc->u.reply.data[6]); - } - rlen = ntohl(rpc->u.reply.data[18]); - if (rlen > len) { - rlen = len; /* shouldn't happen... */ - } - - err = fnc((char *)&rpc->u.reply.data[19], block, rlen, - (offs+rlen == size)); - if (err <= 0) { - nfs_umountall(ARP_SERVER); - return err; - } - - block++; - offs += rlen; - /* last request is done with matching requested read size */ - if (size-offs < NFS_READ_SIZE) { - len = size-offs; - } - } while (len != 0); - /* len == 0 means that all the file has been read */ - return 1; -} - -#endif /* DOWNLOAD_PROTO_NFS */ diff --git a/src/core/proto_http.c b/src/core/proto_http.c deleted file mode 100644 index f2dc9dd18..000000000 --- a/src/core/proto_http.c +++ /dev/null @@ -1,206 +0,0 @@ -#include "etherboot.h" -#include "http.h" - -#ifdef DOWNLOAD_PROTO_HTTP - -/* The block size is currently chosen to be 512 bytes. This means, we can - allocate the receive buffer on the stack, but it results in a noticeable - performance penalty. - This is what needs to be done in order to increase the block size: - - size negotiation needs to be implemented in TCP - - the buffer needs to be allocated on the heap - - path MTU discovery needs to be implemented -*/ /***/ /* FIXME */ -#define BLOCKSIZE TFTP_DEFAULTSIZE_PACKET - -/************************************************************************** -SEND_TCP_CALLBACK - Send data using TCP -**************************************************************************/ -struct send_recv_state { - int (*fnc)(unsigned char *data, int block, int len, int eof); - char *send_buffer; - char *recv_buffer; - int send_length; - int recv_length; - int bytes_sent; - int block; - int bytes_received; - enum { RESULT_CODE, HEADER, DATA, ERROR, MOVED } recv_state; - int rc; - char location[MAX_URL+1]; -}; - -static int send_tcp_request(int length, void *buffer, void *ptr) { - struct send_recv_state *state = (struct send_recv_state *)ptr; - - if (length > state->send_length - state->bytes_sent) - length = state->send_length - state->bytes_sent; - memcpy(buffer, state->send_buffer + state->bytes_sent, length); - state->bytes_sent += length; - return (length); -} - -/************************************************************************** -RECV_TCP_CALLBACK - Receive data using TCP -**************************************************************************/ -static int recv_tcp_request(int length, const void *buffer, void *ptr) { - struct send_recv_state *state = (struct send_recv_state *)ptr; - - /* Assume that the lines in an HTTP header do not straddle a packet */ - /* boundary. This is probably a reasonable assumption */ - if (state->recv_state == RESULT_CODE) { - while (length > 0) { - /* Find HTTP result code */ - if (*(const char *)buffer == ' ') { - const char *ptr = ((const char *)buffer) + 1; - int rc = strtoul(ptr, &ptr, 10); - if (ptr >= (const char *)buffer + length) { - state->recv_state = ERROR; - return 0; - } - state->rc = rc; - state->recv_state = HEADER; - goto header; - } - ++(const char *)buffer; - length--; - } - state->recv_state = ERROR; - return 0; - } - if (state->recv_state == HEADER) { - header: while (length > 0) { - /* Check for HTTP redirect */ - if (state->rc >= 300 && state->rc < 400 && - !memcmp(buffer, "Location: ", 10)) { - char *ptr = state->location; - int i; - memcpy(ptr, buffer + 10, MAX_URL); - for (i = 0; i < MAX_URL && *ptr > ' '; - i++, ptr++); - *ptr = '\000'; - state->recv_state = MOVED; - return 1; - } - /* Find beginning of line */ - while (length > 0) { - length--; - if (*((const char *)buffer)++ == '\n') - break; - } - /* Check for end of header */ - if (length >= 2 && !memcmp(buffer, "\r\n", 2)) { - state->recv_state = DATA; - buffer += 2; - length -= 2; - break; - } - } - } - if (state->recv_state == DATA) { - state->bytes_received += length; - while (length > 0) { - int copy_length = BLOCKSIZE - state->recv_length; - if (copy_length > length) - copy_length = length; - memcpy(state->recv_buffer + state->recv_length, - buffer, copy_length); - if ((state->recv_length += copy_length) == BLOCKSIZE) { - if (!state->fnc(state->recv_buffer, - ++state->block, BLOCKSIZE, 0)) - return 0; - state->recv_length = 0; - } - length -= copy_length; - buffer += copy_length; - } - } - return 1; -} - -/************************************************************************** -HTTP_GET - Get data using HTTP -**************************************************************************/ -int http(const char *url, - int (*fnc)(unsigned char *, unsigned int, unsigned int, int)) { - static const char GET[] = "GET /%s HTTP/1.0\r\n\r\n"; - static char recv_buffer[BLOCKSIZE]; - in_addr destip; - int port; - int length; - struct send_recv_state state; - - state.fnc = fnc; - state.rc = -1; - state.block = 0; - state.recv_buffer = recv_buffer; - length = strlen(url); - if (length <= MAX_URL) { - memcpy(state.location, url, length+1); - destip = arptable[ARP_SERVER].ipaddr; - port = url_port; - if (port == -1) - port = 80; - goto first_time; - - do { - state.rc = -1; - state.block = 0; - url = state.location; - if (memcmp("http://", url, 7)) - break; - url += 7; - length = inet_aton(url, &destip); - if (!length) { - /* As we do not have support for DNS, assume*/ - /* that HTTP redirects always point to the */ - /* same machine */ - if (state.recv_state == MOVED) { - while (*url && - *url != ':' && *url != '/') url++; - } else { - break; - } - } - if (*(url += length) == ':') { - port = strtoul(url, &url, 10); - } else { - port = 80; - } - if (!*url) - url = "/"; - if (*url != '/') - break; - url++; - - first_time: - length = strlen(url); - state.send_length = sizeof(GET) - 3 + length; - - { char buf[state.send_length + 1]; - sprintf(state.send_buffer = buf, GET, url); - state.bytes_sent = 0; - - state.bytes_received = 0; - state.recv_state = RESULT_CODE; - - state.recv_length = 0; - tcp_transaction(destip.s_addr, 80, &state, - send_tcp_request, recv_tcp_request); - } - } while (state.recv_state == MOVED); - } else { - memcpy(state.location, url, MAX_URL); - state.location[MAX_URL] = '\000'; - } - - if (state.rc == 200) { - return fnc(recv_buffer, ++state.block, state.recv_length, 1); - } else { - printf("Failed to download %s (rc = %d)\n", - state.location, state.rc); - return 0; - } -} - -#endif /* DOWNLOAD_PROTO_HTTP */ diff --git a/src/core/proto_slam.c b/src/core/proto_slam.c deleted file mode 100644 index 135384a9c..000000000 --- a/src/core/proto_slam.c +++ /dev/null @@ -1,541 +0,0 @@ -#ifdef DOWNLOAD_PROTO_SLAM -#include "etherboot.h" -#include "nic.h" - -#define SLAM_PORT 10000 -#define SLAM_MULTICAST_IP ((239<<24)|(255<<16)|(1<<8)|(1<<0)) -#define SLAM_MULTICAST_PORT 10000 -#define SLAM_LOCAL_PORT 10000 - -/* Set the timeout intervals to at least 1 second so - * on a 100Mbit ethernet can receive 10000 packets - * in one second. - * - * The only case that is likely to trigger all of the nodes - * firing a nack packet is a slow server. The odds of this - * happening could be reduced being slightly smarter and utilizing - * the multicast channels for nacks. But that only improves the odds - * it doesn't improve the worst case. So unless this proves to be - * a common case having the control data going unicast should increase - * the odds of the data not being dropped. - * - * When doing exponential backoff we increase just the timeout - * interval and not the base to optimize for throughput. This is only - * expected to happen when the server is down. So having some nodes - * pinging immediately should get the transmission restarted quickly after a - * server restart. The host nic won't be to baddly swamped because of - * the random distribution of the nodes. - * - */ -#define SLAM_INITIAL_MIN_TIMEOUT (TICKS_PER_SEC/3) -#define SLAM_INITIAL_TIMEOUT_INTERVAL (TICKS_PER_SEC) -#define SLAM_BASE_MIN_TIMEOUT (2*TICKS_PER_SEC) -#define SLAM_BASE_TIMEOUT_INTERVAL (4*TICKS_PER_SEC) -#define SLAM_BACKOFF_LIMIT 5 -#define SLAM_MAX_RETRIES 20 - -/*** Packets Formats *** - * Data Packet: - * transaction - * total bytes - * block size - * packet # - * data - * - * Status Request Packet - * transaction - * total bytes - * block size - * - * Status Packet - * received packets - * requested packets - * received packets - * requested packets - * ... - * received packets - * requested packtes - * 0 - */ - -#define MAX_HDR (7 + 7 + 7) /* transaction, total size, block size */ -#define MIN_HDR (1 + 1 + 1) /* transactino, total size, block size */ - -#define MAX_SLAM_REQUEST MAX_HDR -#define MIN_SLAM_REQUEST MIN_HDR - -#define MIN_SLAM_DATA (MIN_HDR + 1) - -static struct slam_nack { - struct iphdr ip; - struct udphdr udp; - unsigned char data[ETH_MAX_MTU - - (sizeof(struct iphdr) + sizeof(struct udphdr))]; -} nack; - -struct slam_state { - unsigned char hdr[MAX_HDR]; - unsigned long hdr_len; - unsigned long block_size; - unsigned long total_bytes; - unsigned long total_packets; - - unsigned long received_packets; - - unsigned char *image; - unsigned char *bitmap; -} state; - - -static void init_slam_state(void) -{ - state.hdr_len = sizeof(state.hdr); - memset(state.hdr, 0, state.hdr_len); - state.block_size = 0; - state.total_packets = 0; - - state.received_packets = 0; - - state.image = 0; - state.bitmap = 0; -} - -struct slam_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; -}; - -#define SLAM_TIMEOUT 0 -#define SLAM_REQUEST 1 -#define SLAM_DATA 2 -static int await_slam(int ival __unused, void *ptr, - unsigned short ptype __unused, struct iphdr *ip, struct udphdr *udp) -{ - struct slam_info *info = ptr; - if (!udp) { - return 0; - } - /* I can receive two kinds of packets here, a multicast data packet, - * or a unicast request for information - */ - /* Check for a data request packet */ - if ((ip->dest.s_addr == arptable[ARP_CLIENT].ipaddr.s_addr) && - (ntohs(udp->dest) == info->local_port) && - (nic.packetlen >= - ETH_HLEN + - sizeof(struct iphdr) + - sizeof(struct udphdr) + - MIN_SLAM_REQUEST)) { - return SLAM_REQUEST; - } - /* Check for a multicast data packet */ - 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) + - MIN_SLAM_DATA)) { - return SLAM_DATA; - } -#if 0 - printf("#"); - printf("dest: %@ port: %d len: %d\n", - ip->dest.s_addr, ntohs(udp->dest), nic.packetlen); -#endif - return 0; - -} - -static int slam_encode( - unsigned char **ptr, unsigned char *end, unsigned long value) -{ - unsigned char *data = *ptr; - int bytes; - bytes = sizeof(value); - while ((bytes > 0) && ((0xff & (value >> ((bytes -1)<<3))) == 0)) { - bytes--; - } - if (bytes <= 0) { - bytes = 1; - } - if (data + bytes >= end) { - return -1; - } - if ((0xe0 & (value >> ((bytes -1)<<3))) == 0) { - /* packed together */ - *data = (bytes << 5) | (value >> ((bytes -1)<<3)); - } else { - bytes++; - *data = (bytes << 5); - } - bytes--; - data++; - while(bytes) { - *(data++) = 0xff & (value >> ((bytes -1)<<3)); - bytes--; - } - *ptr = data; - return 0; -} - -static int slam_skip(unsigned char **ptr, unsigned char *end) -{ - int bytes; - if (*ptr >= end) { - return -1; - } - bytes = ((**ptr) >> 5) & 7; - if (bytes == 0) { - return -1; - } - if (*ptr + bytes >= end) { - return -1; - } - (*ptr) += bytes; - return 0; - -} - -static unsigned long slam_decode(unsigned char **ptr, unsigned char *end, int *err) -{ - unsigned long value; - unsigned bytes; - if (*ptr >= end) { - *err = -1; - } - bytes = ((**ptr) >> 5) & 7; - if ((bytes == 0) || (bytes > sizeof(unsigned long))) { - *err = -1; - return 0; - } - if ((*ptr) + bytes >= end) { - *err = -1; - } - value = (**ptr) & 0x1f; - bytes--; - (*ptr)++; - while(bytes) { - value <<= 8; - value |= **ptr; - (*ptr)++; - bytes--; - } - return value; -} - - -static long slam_sleep_interval(int exp) -{ - long range; - long divisor; - long interval; - range = SLAM_BASE_TIMEOUT_INTERVAL; - if (exp < 0) { - divisor = RAND_MAX/SLAM_INITIAL_TIMEOUT_INTERVAL; - } else { - if (exp > SLAM_BACKOFF_LIMIT) - exp = SLAM_BACKOFF_LIMIT; - divisor = RAND_MAX/(range << exp); - } - interval = random()/divisor; - if (exp < 0) { - interval += SLAM_INITIAL_MIN_TIMEOUT; - } else { - interval += SLAM_BASE_MIN_TIMEOUT; - } - return interval; -} - - -static unsigned char *reinit_slam_state( - unsigned char *header, unsigned char *end) -{ - unsigned long total_bytes; - unsigned long block_size; - - unsigned long bitmap_len; - unsigned long max_packet_len; - unsigned char *data; - int err; - -#if 0 - printf("reinit\n"); -#endif - data = header; - - state.hdr_len = 0; - err = slam_skip(&data, end); /* transaction id */ - total_bytes = slam_decode(&data, end, &err); - block_size = slam_decode(&data, end, &err); - if (err) { - printf("ALERT: slam size out of range\n"); - return 0; - } - state.block_size = block_size; - state.total_bytes = total_bytes; - state.total_packets = (total_bytes + block_size - 1)/block_size; - state.hdr_len = data - header; - state.received_packets = 0; - - data = state.hdr; - slam_encode(&data, &state.hdr[sizeof(state.hdr)], state.total_packets); - max_packet_len = data - state.hdr; - memcpy(state.hdr, header, state.hdr_len); - -#if 0 - printf("block_size: %ld\n", block_size); - printf("total_bytes: %ld\n", total_bytes); - printf("total_packets: %ld\n", state.total_packets); - printf("hdr_len: %ld\n", state.hdr_len); - printf("max_packet_len: %ld\n", max_packet_len); -#endif - - if (state.block_size > ETH_MAX_MTU - ( - sizeof(struct iphdr) + sizeof(struct udphdr) + - state.hdr_len + max_packet_len)) { - printf("ALERT: slam blocksize to large\n"); - return 0; - } - if (state.bitmap) { - forget(state.bitmap); - } - bitmap_len = (state.total_packets + 1 + 7)/8; - state.bitmap = allot(bitmap_len); - state.image = allot(total_bytes); - if ((unsigned long)state.image < 1024*1024) { - printf("ALERT: slam filesize to large for available memory\n"); - return 0; - } - memset(state.bitmap, 0, bitmap_len); - - return header + state.hdr_len; -} - -static int slam_recv_data(unsigned char *data) -{ - unsigned long packet; - unsigned long data_len; - int err; - struct udphdr *udp; - udp = (struct udphdr *)&nic.packet[ETH_HLEN + sizeof(struct iphdr)]; - err = 0; - packet = slam_decode(&data, &nic.packet[nic.packetlen], &err); - if (err || (packet > state.total_packets)) { - printf("ALERT: Invalid packet number\n"); - return 0; - } - /* Compute the expected data length */ - if (packet != state.total_packets -1) { - data_len = state.block_size; - } else { - data_len = state.total_bytes % 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\n"); - return 1; - } - if (nic.packetlen < data_len + (data - nic.packet)) { - printf("ALERT: Ethernet packet shorter than data_len\n"); - return 1; - } - if (data_len > state.block_size) { - data_len = state.block_size; - } - if (((state.bitmap[packet >> 3] >> (packet & 7)) & 1) == 0) { - /* Non duplicate packet */ - state.bitmap[packet >> 3] |= (1 << (packet & 7)); - memcpy(state.image + (packet*state.block_size), data, data_len); - state.received_packets++; - } else { -#ifdef MDEBUG - printf("\n"); -#endif - } - return 1; -} - -static void transmit_nack(unsigned char *ptr, struct slam_info *info) -{ - int nack_len; - /* Ensure the packet is null terminated */ - *ptr++ = 0; - nack_len = ptr - (unsigned char *)&nack; - build_udp_hdr(info->server_ip.s_addr, - info->local_port, info->server_port, 1, nack_len, &nack); - ip_transmit(nack_len, &nack); -#if defined(MDEBUG) && 0 - printf("Sent NACK to %@ bytes: %d have:%ld/%ld\n", - info->server_ip, nack_len, - state.received_packets, state.total_packets); -#endif -} - -static void slam_send_nack(struct slam_info *info) -{ - unsigned char *ptr, *end; - /* Either I timed out or I was explicitly - * asked for a request packet - */ - ptr = &nack.data[0]; - /* Reserve space for the trailling null */ - end = &nack.data[sizeof(nack.data) -1]; - if (!state.bitmap) { - slam_encode(&ptr, end, 0); - slam_encode(&ptr, end, 1); - } - else { - /* Walk the bitmap */ - unsigned long i; - unsigned long len; - unsigned long max; - int value; - int last; - /* Compute the last bit and store an inverted trailer */ - max = state.total_packets; - 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 = 1; /* Start with the received packets */ - for(i = 0; i <= max; i++) { - value = (state.bitmap[i>>3] >> (i & 7)) & 1; - if (value == last) { - len++; - } else { - if (slam_encode(&ptr, end, len)) - break; - last = value; - len = 1; - } - } - } - info->sent_nack = 1; - transmit_nack(ptr, info); -} - -static void slam_send_disconnect(struct slam_info *info) -{ - if (info->sent_nack) { - /* A disconnect is a packet with just the null terminator */ - transmit_nack(&nack.data[0], info); - } - info->sent_nack = 0; -} - - -static int proto_slam(struct slam_info *info) -{ - int retry; - long timeout; - - init_slam_state(); - - retry = -1; - rx_qdrain(); - /* Arp for my server */ - if (arptable[ARP_SERVER].ipaddr.s_addr != info->server_ip.s_addr) { - arptable[ARP_SERVER].ipaddr.s_addr = info->server_ip.s_addr; - memset(arptable[ARP_SERVER].node, 0, ETH_ALEN); - } - /* If I'm running over multicast join the multicast group */ - join_group(IGMP_SERVER, info->multicast_ip.s_addr); - for(;;) { - unsigned char *header; - unsigned char *data; - int type; - header = data = 0; - - timeout = slam_sleep_interval(retry); - type = await_reply(await_slam, 0, info, timeout); - /* Compute the timeout for next time */ - if (type == SLAM_TIMEOUT) { - /* If I timeouted recompute the next timeout */ - if (retry++ > SLAM_MAX_RETRIES) { - return 0; - } - } else { - retry = 0; - } - if ((type == SLAM_DATA) || (type == SLAM_REQUEST)) { - /* Check the incomming packet and reinit the data - * structures if necessary. - */ - header = &nic.packet[ETH_HLEN + - sizeof(struct iphdr) + sizeof(struct udphdr)]; - data = header + state.hdr_len; - if (memcmp(state.hdr, header, state.hdr_len) != 0) { - /* Something is fishy reset the transaction */ - data = reinit_slam_state(header, &nic.packet[nic.packetlen]); - if (!data) { - return 0; - } - } - } - if (type == SLAM_DATA) { - if (!slam_recv_data(data)) { - return 0; - } - if (state.received_packets == state.total_packets) { - /* We are done get out */ - break; - } - } - if ((type == SLAM_TIMEOUT) || (type == SLAM_REQUEST)) { - /* Either I timed out or I was explicitly - * asked by a request packet - */ - slam_send_nack(info); - } - } - slam_send_disconnect(info); - - /* Leave the multicast group */ - leave_group(IGMP_SERVER); - /* FIXME don't overwrite myself */ - /* load file to correct location */ - return info->fnc(state.image, 1, state.total_bytes, 1); -} - - -int url_slam(const char *name, int (*fnc)(unsigned char *, unsigned int, unsigned int, int)) -{ - struct slam_info info; - /* Set the defaults */ - info.server_ip.s_addr = arptable[ARP_SERVER].ipaddr.s_addr; - info.server_port = SLAM_PORT; - info.multicast_ip.s_addr = htonl(SLAM_MULTICAST_IP); - info.multicast_port = SLAM_MULTICAST_PORT; - info.local_ip.s_addr = arptable[ARP_CLIENT].ipaddr.s_addr; - info.local_port = SLAM_LOCAL_PORT; - info.fnc = fnc; - info.sent_nack = 0; - /* Now parse the url */ - if (url_port != -1) { - info.server_port = url_port; - } - if (name[0]) { - /* multicast ip */ - name += inet_aton(name, &info.multicast_ip); - if (name[0] == ':') { - name++; - info.multicast_port = strtoul(name, &name, 10); - } - } - if (name[0]) { - printf("\nBad url\n"); - return 0; - } - return proto_slam(&info); -} - -#endif /* DOWNLOAD_PROTO_SLAM */ 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 -* -* 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("\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("\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 */ -- cgit v1.2.3-55-g7522