Files
seta75D 2e8a93c394 Init
2021-10-11 18:20:23 -03:00

204 lines
4.6 KiB
C

/* @(#)tftp.c 1.1 92/07/30 SMI */
/*
* Bare-bones tftp implementation for sun2's with ND in proms
*/
#include "../lib/common/saio.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <netinet/in_systm.h>
#include <netinet/if_ether.h>
#include <netinet/ip_var.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netinet/udp_var.h>
#include "../lib/common/sainet.h"
#include <arpa/tftp.h>
#define MAXNAMELEN 8 /* 8 bytes of internet address in hex */
#define UDP_OFFSET \
(sizeof(struct udphdr)+sizeof(struct ip)+sizeof(struct ether_header))
#define MAXSENDSIZE (4 + MAXNAMELEN + 1 + sizeof(mode))
#define MAXRECVSIZE (4 + SEGSIZE)
#define millitime() (*romp->v_nmiclock)
#define flipit() putchar(flip[flipc++ % 4]); putchar('\b')
extern int random;
char mode[] = "octet"; /* transfer mode is always octet */
char flip[] = "-\\|/"; /* emulates what the proms do */
int flipc = 0; /* current location in flip */
int sport = -1; /* source port */
char sendpacket[UDP_OFFSET + MAXSENDSIZE];
char recvpacket[ETHERMTU];
/*
* Use tftp to read in a file
*/
tftpread(rhost, rether, name, mem, timeout, retries)
struct sockaddr_in rhost;
struct ether_addr rether;
char *name;
char *mem;
int timeout; /* timeout per request */
int retries; /* number of retries before giving up */
{
int sendsize;
int recvsize;
struct tftphdr *sendth;
struct tftphdr *recvth;
int lastblock;
int amount;
int nrecv;
int stoprecv;
int eof;
int gotblock;
int tries;
struct sockaddr_in thost;
struct ether_addr tether;
recvth = (struct tftphdr *) (recvpacket + UDP_OFFSET);
sendth = (struct tftphdr *) (sendpacket + UDP_OFFSET);
eof = 0;
tries = 0;
if (sport >= 0) {
sendth->th_opcode = htons(ACK);
sendth->th_block = 1;
sendsize = 4;
amount = SEGSIZE;
lastblock = 1;
} else {
sport = random++ & 0xffff;
amount = 0;
lastblock = 0;
rhost.sin_port = IPPORT_TFTP;
sendsize = makereq(sendth, name);
}
while ((! eof) && (tries++ < retries)) {
(void) udp_output(&rhost, &rether, (u_short) sport, sendpacket,
sendsize);
flipit();
gotblock = 0;
stoprecv = millitime() + timeout;
while ((! gotblock) && (millitime() < stoprecv)) {
recvsize = MAXRECVSIZE;
nrecv = udp_input(&thost, &tether, (u_short) sport,
recvpacket, recvsize);
if (thost.sin_addr.s_addr == rhost.sin_addr.s_addr &&
nrecv >= 4)
{
switch (ntohs(recvth->th_opcode)) {
case DATA:
if (ntohs(recvth->th_block) ==
lastblock + 1)
{
gotblock = 1;
}
break;
case ERROR:
return(-1);
}
}
}
if (gotblock) {
flipit();
recvsize = nrecv - 4;
bcopy(recvth->th_data, mem + amount, recvsize);
amount += recvsize;
if (recvsize == SEGSIZE) {
sendth->th_opcode = htons(ACK);
sendth->th_block = recvth->th_block;
lastblock = ntohs(recvth->th_block);
sendsize = 4;
tries = 0;
} else {
eof = 1;
}
rhost.sin_port = thost.sin_port;
}
}
if (eof) {
printf("Downloaded %d bytes from tftp server.\n", amount);
}
return(eof ? amount : 0);
}
/*
* Find a tftp server by broadcasting
* Read in the first block, if one is received
*/
tftpfind(rhost, rether, name, mem, timeout)
struct sockaddr_in *rhost;
struct ether_addr *rether;
char *name;
char *mem;
int timeout;
{
struct tftphdr *sendth;
struct tftphdr *recvth;
struct sockaddr_in thost;
struct ether_addr tether;
extern struct sainet ether_sain;
extern struct ether_addr etherbroadcastaddr;
int nrecv;
int sendsize;
int stoprecv;
int recvsize;
recvth = (struct tftphdr *) (recvpacket + UDP_OFFSET);
sendth = (struct tftphdr *) (sendpacket + UDP_OFFSET);
sendsize = makereq(sendth, name);
sport = random++ & 0xffff;
thost.sin_port = IPPORT_TFTP;
thost.sin_addr.s_addr = ~0;
tether = etherbroadcastaddr;
(void) udp_output(&thost, &tether, (u_short) sport, sendpacket,
sendsize);
flipit();
stoprecv = millitime() + timeout;
while (millitime() < stoprecv) {
nrecv = udp_input(rhost, rether, (u_short) sport,
recvpacket, MAXRECVSIZE);
if (nrecv >= 4 && ntohs(recvth->th_opcode) == DATA
&& ntohs(recvth->th_block) == 1)
{
flipit();
recvsize = nrecv - 4;
bcopy(recvth->th_data, mem, recvsize);
return(recvsize != SEGSIZE);
}
}
return(-1);
}
char *
strput(dst, src)
char *dst;
char *src;
{
while (*dst++ = *src++)
;
return(dst);
}
makereq(sendth, name)
struct tftphdr *sendth;
char *name;
{
char *cp;
sendth->th_opcode = htons(RRQ);
cp = strput(sendth->th_stuff, name);
cp = strput(cp, mode);
return(sizeof(sendth->th_opcode) + (cp - sendth->th_stuff));
}