summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
authorMichael Brown2005-05-01 16:04:11 +0200
committerMichael Brown2005-05-01 16:04:11 +0200
commit85d9eae44ef5e2c48fcbefe36fb7bdfcb54c9f75 (patch)
tree00a1194278710abe5021f8bf00236ca41b14d087 /src/core
parentAbort immediately if no nameserver is present. (diff)
downloadipxe-85d9eae44ef5e2c48fcbefe36fb7bdfcb54c9f75.tar.gz
ipxe-85d9eae44ef5e2c48fcbefe36fb7bdfcb54c9f75.tar.xz
ipxe-85d9eae44ef5e2c48fcbefe36fb7bdfcb54c9f75.zip
Moved protocols to proto/
Diffstat (limited to 'src/core')
-rw-r--r--src/core/nfs.c610
-rw-r--r--src/core/proto_http.c206
-rw-r--r--src/core/proto_slam.c541
-rw-r--r--src/core/proto_tftm.c491
4 files changed, 0 insertions, 1848 deletions
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("<DUP>\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 <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 */