1*cf5a6c84SAndroid Build Coastguard Worker /* tftp.c - TFTP client.
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2012 Madhur Verma <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2015 Sameer Prakash Pradhan <[email protected]>
5*cf5a6c84SAndroid Build Coastguard Worker *
6*cf5a6c84SAndroid Build Coastguard Worker * No Standard.
7*cf5a6c84SAndroid Build Coastguard Worker
8*cf5a6c84SAndroid Build Coastguard Worker USE_TFTP(NEWTOY(tftp, "<1b#<8>65464r:l:g|p|[!gp]", TOYFLAG_USR|TOYFLAG_BIN))
9*cf5a6c84SAndroid Build Coastguard Worker
10*cf5a6c84SAndroid Build Coastguard Worker config TFTP
11*cf5a6c84SAndroid Build Coastguard Worker bool "tftp"
12*cf5a6c84SAndroid Build Coastguard Worker default n
13*cf5a6c84SAndroid Build Coastguard Worker help
14*cf5a6c84SAndroid Build Coastguard Worker usage: tftp [OPTIONS] HOST [PORT]
15*cf5a6c84SAndroid Build Coastguard Worker
16*cf5a6c84SAndroid Build Coastguard Worker Transfer file from/to tftp server.
17*cf5a6c84SAndroid Build Coastguard Worker
18*cf5a6c84SAndroid Build Coastguard Worker -l FILE Local FILE
19*cf5a6c84SAndroid Build Coastguard Worker -r FILE Remote FILE
20*cf5a6c84SAndroid Build Coastguard Worker -g Get file
21*cf5a6c84SAndroid Build Coastguard Worker -p Put file
22*cf5a6c84SAndroid Build Coastguard Worker -b SIZE Transfer blocks of SIZE octets(8 <= SIZE <= 65464)
23*cf5a6c84SAndroid Build Coastguard Worker */
24*cf5a6c84SAndroid Build Coastguard Worker #define FOR_tftp
25*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
26*cf5a6c84SAndroid Build Coastguard Worker
GLOBALS(char * local_file;char * remote_file;long block_size;struct sockaddr_storage inaddr;int af;)27*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
28*cf5a6c84SAndroid Build Coastguard Worker char *local_file;
29*cf5a6c84SAndroid Build Coastguard Worker char *remote_file;
30*cf5a6c84SAndroid Build Coastguard Worker long block_size;
31*cf5a6c84SAndroid Build Coastguard Worker
32*cf5a6c84SAndroid Build Coastguard Worker struct sockaddr_storage inaddr;
33*cf5a6c84SAndroid Build Coastguard Worker int af;
34*cf5a6c84SAndroid Build Coastguard Worker )
35*cf5a6c84SAndroid Build Coastguard Worker
36*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_BLKSIZE 512
37*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_RETRIES 3
38*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_DATAHEADERSIZE 4
39*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_MAXPACKETSIZE (TFTP_DATAHEADERSIZE + TFTP_BLKSIZE)
40*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_PACKETSIZE TFTP_MAXPACKETSIZE
41*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_DATASIZE (TFTP_PACKETSIZE-TFTP_DATAHEADERSIZE)
42*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_IOBUFSIZE (TFTP_PACKETSIZE+8)
43*cf5a6c84SAndroid Build Coastguard Worker
44*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_OP_RRQ 1 /* Read Request RFC 1350, RFC 2090 */
45*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_OP_WRQ 2 /* Write Request RFC 1350 */
46*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_OP_DATA 3 /* Data chunk RFC 1350 */
47*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_OP_ACK 4 /* Acknowledgement RFC 1350 */
48*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_OP_ERR 5 /* Error Message RFC 1350 */
49*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_OP_OACK 6 /* Option acknowledgment RFC 2347 */
50*cf5a6c84SAndroid Build Coastguard Worker
51*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_ER_ILLEGALOP 4 /* Illegal TFTP operation */
52*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_ER_UNKID 5 /* Unknown transfer ID */
53*cf5a6c84SAndroid Build Coastguard Worker
54*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_ES_NOSUCHFILE "File not found"
55*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_ES_ACCESS "Access violation"
56*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_ES_FULL "Disk full or allocation exceeded"
57*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_ES_ILLEGALOP "Illegal TFTP operation"
58*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_ES_UNKID "Unknown transfer ID"
59*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_ES_EXISTS "File already exists"
60*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_ES_UNKUSER "No such user"
61*cf5a6c84SAndroid Build Coastguard Worker #define TFTP_ES_NEGOTIATE "Terminate transfer due to option negotiation"
62*cf5a6c84SAndroid Build Coastguard Worker
63*cf5a6c84SAndroid Build Coastguard Worker // Initializes SERVER with ADDR and returns socket.
64*cf5a6c84SAndroid Build Coastguard Worker static int init_tftp(struct sockaddr_storage *server)
65*cf5a6c84SAndroid Build Coastguard Worker {
66*cf5a6c84SAndroid Build Coastguard Worker struct timeval to = { .tv_sec = 10, //Time out
67*cf5a6c84SAndroid Build Coastguard Worker .tv_usec = 0 };
68*cf5a6c84SAndroid Build Coastguard Worker const int set = 1;
69*cf5a6c84SAndroid Build Coastguard Worker int port = 69, sd = xsocket(TT.af, SOCK_DGRAM, IPPROTO_UDP);
70*cf5a6c84SAndroid Build Coastguard Worker
71*cf5a6c84SAndroid Build Coastguard Worker xsetsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (void *)&to, sizeof(struct timeval));
72*cf5a6c84SAndroid Build Coastguard Worker xsetsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (void *)&set, sizeof(set));
73*cf5a6c84SAndroid Build Coastguard Worker
74*cf5a6c84SAndroid Build Coastguard Worker if(toys.optc == 2) port = atolx_range(toys.optargs[1], 1, 65535);
75*cf5a6c84SAndroid Build Coastguard Worker memset(server, 0, sizeof(struct sockaddr_storage));
76*cf5a6c84SAndroid Build Coastguard Worker if (TT.af == AF_INET6) {
77*cf5a6c84SAndroid Build Coastguard Worker ((struct sockaddr_in6 *)server)->sin6_family = AF_INET6;
78*cf5a6c84SAndroid Build Coastguard Worker ((struct sockaddr_in6 *)server)->sin6_addr =
79*cf5a6c84SAndroid Build Coastguard Worker ((struct sockaddr_in6 *)&TT.inaddr)->sin6_addr;
80*cf5a6c84SAndroid Build Coastguard Worker ((struct sockaddr_in6 *)server)->sin6_port = htons(port);
81*cf5a6c84SAndroid Build Coastguard Worker }
82*cf5a6c84SAndroid Build Coastguard Worker else {
83*cf5a6c84SAndroid Build Coastguard Worker ((struct sockaddr_in *)server)->sin_family = AF_INET;
84*cf5a6c84SAndroid Build Coastguard Worker ((struct sockaddr_in *)server)->sin_addr.s_addr =
85*cf5a6c84SAndroid Build Coastguard Worker ((struct sockaddr_in *)&TT.inaddr)->sin_addr.s_addr;
86*cf5a6c84SAndroid Build Coastguard Worker ((struct sockaddr_in *)server)->sin_port = htons(port);
87*cf5a6c84SAndroid Build Coastguard Worker }
88*cf5a6c84SAndroid Build Coastguard Worker return sd;
89*cf5a6c84SAndroid Build Coastguard Worker }
90*cf5a6c84SAndroid Build Coastguard Worker
91*cf5a6c84SAndroid Build Coastguard Worker /*
92*cf5a6c84SAndroid Build Coastguard Worker * Makes a request packet in BUFFER with OPCODE and file PATH of MODE
93*cf5a6c84SAndroid Build Coastguard Worker * and returns length of packet.
94*cf5a6c84SAndroid Build Coastguard Worker */
mkpkt_request(uint8_t * buffer,int opcode,char * path,int mode)95*cf5a6c84SAndroid Build Coastguard Worker static int mkpkt_request(uint8_t *buffer, int opcode, char *path, int mode)
96*cf5a6c84SAndroid Build Coastguard Worker {
97*cf5a6c84SAndroid Build Coastguard Worker buffer[0] = opcode >> 8;
98*cf5a6c84SAndroid Build Coastguard Worker buffer[1] = opcode & 0xff;
99*cf5a6c84SAndroid Build Coastguard Worker if(strlen(path) > TFTP_BLKSIZE) error_exit("path too long");
100*cf5a6c84SAndroid Build Coastguard Worker return sprintf((char*) &buffer[2], "%s%c%s", path, 0,
101*cf5a6c84SAndroid Build Coastguard Worker (mode ? "octet" : "netascii")) + 3;
102*cf5a6c84SAndroid Build Coastguard Worker }
103*cf5a6c84SAndroid Build Coastguard Worker
104*cf5a6c84SAndroid Build Coastguard Worker /*
105*cf5a6c84SAndroid Build Coastguard Worker * Makes an acknowledgement packet in BUFFER of BLOCNO
106*cf5a6c84SAndroid Build Coastguard Worker * and returns packet length.
107*cf5a6c84SAndroid Build Coastguard Worker */
mkpkt_ack(uint8_t * buffer,uint16_t blockno)108*cf5a6c84SAndroid Build Coastguard Worker static int mkpkt_ack(uint8_t *buffer, uint16_t blockno)
109*cf5a6c84SAndroid Build Coastguard Worker {
110*cf5a6c84SAndroid Build Coastguard Worker buffer[0] = TFTP_OP_ACK >> 8;
111*cf5a6c84SAndroid Build Coastguard Worker buffer[1] = TFTP_OP_ACK & 0xff;
112*cf5a6c84SAndroid Build Coastguard Worker buffer[2] = blockno >> 8;
113*cf5a6c84SAndroid Build Coastguard Worker buffer[3] = blockno & 0xff;
114*cf5a6c84SAndroid Build Coastguard Worker return 4;
115*cf5a6c84SAndroid Build Coastguard Worker }
116*cf5a6c84SAndroid Build Coastguard Worker
117*cf5a6c84SAndroid Build Coastguard Worker /*
118*cf5a6c84SAndroid Build Coastguard Worker * Makes an error packet in BUFFER with ERRORCODE and ERRORMSG.
119*cf5a6c84SAndroid Build Coastguard Worker * and returns packet length.
120*cf5a6c84SAndroid Build Coastguard Worker */
mkpkt_err(uint8_t * buffer,uint16_t errorcode,char * errormsg)121*cf5a6c84SAndroid Build Coastguard Worker static int mkpkt_err(uint8_t *buffer, uint16_t errorcode, char *errormsg)
122*cf5a6c84SAndroid Build Coastguard Worker {
123*cf5a6c84SAndroid Build Coastguard Worker buffer[0] = TFTP_OP_ERR >> 8;
124*cf5a6c84SAndroid Build Coastguard Worker buffer[1] = TFTP_OP_ERR & 0xff;
125*cf5a6c84SAndroid Build Coastguard Worker buffer[2] = errorcode >> 8;
126*cf5a6c84SAndroid Build Coastguard Worker buffer[3] = errorcode & 0xff;
127*cf5a6c84SAndroid Build Coastguard Worker strcpy((char*) &buffer[4], errormsg);
128*cf5a6c84SAndroid Build Coastguard Worker return strlen(errormsg) + 5;
129*cf5a6c84SAndroid Build Coastguard Worker }
130*cf5a6c84SAndroid Build Coastguard Worker
131*cf5a6c84SAndroid Build Coastguard Worker /*
132*cf5a6c84SAndroid Build Coastguard Worker * Recieves data from server in BUFF with socket SD and updates FROM
133*cf5a6c84SAndroid Build Coastguard Worker * and returns read length.
134*cf5a6c84SAndroid Build Coastguard Worker */
read_server(int sd,void * buf,int len,struct sockaddr_storage * from)135*cf5a6c84SAndroid Build Coastguard Worker static int read_server(int sd, void *buf, int len,
136*cf5a6c84SAndroid Build Coastguard Worker struct sockaddr_storage *from)
137*cf5a6c84SAndroid Build Coastguard Worker {
138*cf5a6c84SAndroid Build Coastguard Worker socklen_t alen;
139*cf5a6c84SAndroid Build Coastguard Worker ssize_t nb;
140*cf5a6c84SAndroid Build Coastguard Worker
141*cf5a6c84SAndroid Build Coastguard Worker for (;;) {
142*cf5a6c84SAndroid Build Coastguard Worker memset(buf, 0, len);
143*cf5a6c84SAndroid Build Coastguard Worker alen = sizeof(struct sockaddr_storage);
144*cf5a6c84SAndroid Build Coastguard Worker nb = recvfrom(sd, buf, len, 0, (struct sockaddr *) from, &alen);
145*cf5a6c84SAndroid Build Coastguard Worker if (nb < 0) {
146*cf5a6c84SAndroid Build Coastguard Worker if (errno == EAGAIN) {
147*cf5a6c84SAndroid Build Coastguard Worker perror_msg("server read timed out");
148*cf5a6c84SAndroid Build Coastguard Worker return nb;
149*cf5a6c84SAndroid Build Coastguard Worker }else if (errno != EINTR) {
150*cf5a6c84SAndroid Build Coastguard Worker perror_msg("server read failed");
151*cf5a6c84SAndroid Build Coastguard Worker return nb;
152*cf5a6c84SAndroid Build Coastguard Worker }
153*cf5a6c84SAndroid Build Coastguard Worker }else return nb;
154*cf5a6c84SAndroid Build Coastguard Worker }
155*cf5a6c84SAndroid Build Coastguard Worker return nb;
156*cf5a6c84SAndroid Build Coastguard Worker }
157*cf5a6c84SAndroid Build Coastguard Worker
158*cf5a6c84SAndroid Build Coastguard Worker /*
159*cf5a6c84SAndroid Build Coastguard Worker * sends data to server TO from BUFF of length LEN through socket SD
160*cf5a6c84SAndroid Build Coastguard Worker * and returns successfully send bytes number.
161*cf5a6c84SAndroid Build Coastguard Worker */
write_server(int sd,void * buf,size_t len,struct sockaddr_storage * to)162*cf5a6c84SAndroid Build Coastguard Worker static ssize_t write_server(int sd, void *buf, size_t len,
163*cf5a6c84SAndroid Build Coastguard Worker struct sockaddr_storage *to)
164*cf5a6c84SAndroid Build Coastguard Worker {
165*cf5a6c84SAndroid Build Coastguard Worker ssize_t nb;
166*cf5a6c84SAndroid Build Coastguard Worker
167*cf5a6c84SAndroid Build Coastguard Worker for (;;) {
168*cf5a6c84SAndroid Build Coastguard Worker nb = sendto(sd, buf, len, 0, (struct sockaddr *)to,
169*cf5a6c84SAndroid Build Coastguard Worker sizeof(struct sockaddr_storage));
170*cf5a6c84SAndroid Build Coastguard Worker if (nb < 0) {
171*cf5a6c84SAndroid Build Coastguard Worker if (errno != EINTR) {
172*cf5a6c84SAndroid Build Coastguard Worker perror_msg("server write failed");
173*cf5a6c84SAndroid Build Coastguard Worker return nb;
174*cf5a6c84SAndroid Build Coastguard Worker }
175*cf5a6c84SAndroid Build Coastguard Worker } else return nb;
176*cf5a6c84SAndroid Build Coastguard Worker }
177*cf5a6c84SAndroid Build Coastguard Worker return nb;
178*cf5a6c84SAndroid Build Coastguard Worker }
179*cf5a6c84SAndroid Build Coastguard Worker
180*cf5a6c84SAndroid Build Coastguard Worker // checks packet for data and updates block no
check_data(uint8_t * packet,uint16_t * opcode,uint16_t * blockno)181*cf5a6c84SAndroid Build Coastguard Worker static inline int check_data( uint8_t *packet, uint16_t *opcode,
182*cf5a6c84SAndroid Build Coastguard Worker uint16_t *blockno)
183*cf5a6c84SAndroid Build Coastguard Worker {
184*cf5a6c84SAndroid Build Coastguard Worker *opcode = (uint16_t) packet[0] << 8 | (uint16_t) packet[1];
185*cf5a6c84SAndroid Build Coastguard Worker if (*opcode == TFTP_OP_DATA) {
186*cf5a6c84SAndroid Build Coastguard Worker *blockno = (uint16_t) packet[2] << 8 | (uint16_t) packet[3];
187*cf5a6c84SAndroid Build Coastguard Worker return 0;
188*cf5a6c84SAndroid Build Coastguard Worker }
189*cf5a6c84SAndroid Build Coastguard Worker return -1;
190*cf5a6c84SAndroid Build Coastguard Worker }
191*cf5a6c84SAndroid Build Coastguard Worker
192*cf5a6c84SAndroid Build Coastguard Worker // Makes data packet through FD from file OFFSET in buffer PACKET of BLOCKNO
mkpkt_data(int fd,off_t offset,uint8_t * packet,uint16_t blockno)193*cf5a6c84SAndroid Build Coastguard Worker static int mkpkt_data(int fd, off_t offset, uint8_t *packet, uint16_t blockno)
194*cf5a6c84SAndroid Build Coastguard Worker {
195*cf5a6c84SAndroid Build Coastguard Worker off_t tmp;
196*cf5a6c84SAndroid Build Coastguard Worker int nbytesread;
197*cf5a6c84SAndroid Build Coastguard Worker
198*cf5a6c84SAndroid Build Coastguard Worker packet[0] = TFTP_OP_DATA >> 8;
199*cf5a6c84SAndroid Build Coastguard Worker packet[1] = TFTP_OP_DATA & 0xff;
200*cf5a6c84SAndroid Build Coastguard Worker packet[2] = blockno >> 8;
201*cf5a6c84SAndroid Build Coastguard Worker packet[3] = blockno & 0xff;
202*cf5a6c84SAndroid Build Coastguard Worker tmp = lseek(fd, offset, SEEK_SET);
203*cf5a6c84SAndroid Build Coastguard Worker if (tmp == (off_t) -1) {
204*cf5a6c84SAndroid Build Coastguard Worker perror_msg("lseek failed");
205*cf5a6c84SAndroid Build Coastguard Worker return -1;
206*cf5a6c84SAndroid Build Coastguard Worker }
207*cf5a6c84SAndroid Build Coastguard Worker nbytesread = readall(fd, &packet[TFTP_DATAHEADERSIZE], TFTP_DATASIZE);
208*cf5a6c84SAndroid Build Coastguard Worker if (nbytesread < 0) return -1;
209*cf5a6c84SAndroid Build Coastguard Worker return nbytesread + TFTP_DATAHEADERSIZE;
210*cf5a6c84SAndroid Build Coastguard Worker }
211*cf5a6c84SAndroid Build Coastguard Worker
212*cf5a6c84SAndroid Build Coastguard Worker // Receives ACK responses from server and updates blockno
read_ack(int sd,uint8_t * packet,struct sockaddr_storage * server,uint16_t * port,uint16_t * blockno)213*cf5a6c84SAndroid Build Coastguard Worker static int read_ack(int sd, uint8_t *packet, struct sockaddr_storage *server,
214*cf5a6c84SAndroid Build Coastguard Worker uint16_t *port, uint16_t *blockno)
215*cf5a6c84SAndroid Build Coastguard Worker {
216*cf5a6c84SAndroid Build Coastguard Worker struct sockaddr_storage from;
217*cf5a6c84SAndroid Build Coastguard Worker int nbytes;
218*cf5a6c84SAndroid Build Coastguard Worker uint16_t opcode, rblockno;
219*cf5a6c84SAndroid Build Coastguard Worker int packetlen, retry;
220*cf5a6c84SAndroid Build Coastguard Worker
221*cf5a6c84SAndroid Build Coastguard Worker for (retry = 0; retry < TFTP_RETRIES; retry++) {
222*cf5a6c84SAndroid Build Coastguard Worker for (;;) {
223*cf5a6c84SAndroid Build Coastguard Worker nbytes = read_server(sd, packet, TFTP_IOBUFSIZE, &from);
224*cf5a6c84SAndroid Build Coastguard Worker if (nbytes < 4) { // Ack headersize = 4
225*cf5a6c84SAndroid Build Coastguard Worker if (nbytes == 0) error_msg("Connection lost.");
226*cf5a6c84SAndroid Build Coastguard Worker else if (nbytes > 0) error_msg("Short packet: %d bytes", nbytes);
227*cf5a6c84SAndroid Build Coastguard Worker else error_msg("Server read ACK failure.");
228*cf5a6c84SAndroid Build Coastguard Worker break;
229*cf5a6c84SAndroid Build Coastguard Worker } else {
230*cf5a6c84SAndroid Build Coastguard Worker if (!*port) {
231*cf5a6c84SAndroid Build Coastguard Worker *port = ((struct sockaddr_in *)&from)->sin_port;
232*cf5a6c84SAndroid Build Coastguard Worker ((struct sockaddr_in *)server)->sin_port =
233*cf5a6c84SAndroid Build Coastguard Worker ((struct sockaddr_in *)&from)->sin_port;
234*cf5a6c84SAndroid Build Coastguard Worker }
235*cf5a6c84SAndroid Build Coastguard Worker if (((struct sockaddr_in *)server)->sin_addr.s_addr !=
236*cf5a6c84SAndroid Build Coastguard Worker ((struct sockaddr_in *)&from)->sin_addr.s_addr) {
237*cf5a6c84SAndroid Build Coastguard Worker error_msg("Invalid address in DATA.");
238*cf5a6c84SAndroid Build Coastguard Worker continue;
239*cf5a6c84SAndroid Build Coastguard Worker }
240*cf5a6c84SAndroid Build Coastguard Worker if (*port != ((struct sockaddr_in *)server)->sin_port) {
241*cf5a6c84SAndroid Build Coastguard Worker error_msg("Invalid port in DATA.");
242*cf5a6c84SAndroid Build Coastguard Worker packetlen = mkpkt_err(packet, TFTP_ER_UNKID, TFTP_ES_UNKID);
243*cf5a6c84SAndroid Build Coastguard Worker (void) write_server(sd, packet, packetlen, server);
244*cf5a6c84SAndroid Build Coastguard Worker continue;
245*cf5a6c84SAndroid Build Coastguard Worker }
246*cf5a6c84SAndroid Build Coastguard Worker opcode = (uint16_t) packet[0] << 8 | (uint16_t) packet[1];
247*cf5a6c84SAndroid Build Coastguard Worker rblockno = (uint16_t) packet[2] << 8 | (uint16_t) packet[3];
248*cf5a6c84SAndroid Build Coastguard Worker
249*cf5a6c84SAndroid Build Coastguard Worker if (opcode != TFTP_OP_ACK) {
250*cf5a6c84SAndroid Build Coastguard Worker error_msg("Bad opcode.");
251*cf5a6c84SAndroid Build Coastguard Worker if (opcode > 5) {
252*cf5a6c84SAndroid Build Coastguard Worker packetlen = mkpkt_err(packet, TFTP_ER_ILLEGALOP, TFTP_ES_ILLEGALOP);
253*cf5a6c84SAndroid Build Coastguard Worker (void) write_server(sd, packet, packetlen, server);
254*cf5a6c84SAndroid Build Coastguard Worker }
255*cf5a6c84SAndroid Build Coastguard Worker break;
256*cf5a6c84SAndroid Build Coastguard Worker }
257*cf5a6c84SAndroid Build Coastguard Worker if (blockno) *blockno = rblockno;
258*cf5a6c84SAndroid Build Coastguard Worker return 0;
259*cf5a6c84SAndroid Build Coastguard Worker }
260*cf5a6c84SAndroid Build Coastguard Worker }
261*cf5a6c84SAndroid Build Coastguard Worker }
262*cf5a6c84SAndroid Build Coastguard Worker error_msg("Timeout, Waiting for ACK.");
263*cf5a6c84SAndroid Build Coastguard Worker return -1;
264*cf5a6c84SAndroid Build Coastguard Worker }
265*cf5a6c84SAndroid Build Coastguard Worker
266*cf5a6c84SAndroid Build Coastguard Worker // receives file from server.
file_get(void)267*cf5a6c84SAndroid Build Coastguard Worker static int file_get(void)
268*cf5a6c84SAndroid Build Coastguard Worker {
269*cf5a6c84SAndroid Build Coastguard Worker struct sockaddr_storage server, from;
270*cf5a6c84SAndroid Build Coastguard Worker uint8_t *packet;
271*cf5a6c84SAndroid Build Coastguard Worker uint16_t blockno = 0, opcode, rblockno = 0;
272*cf5a6c84SAndroid Build Coastguard Worker int len, sd, fd, retry, nbytesrecvd = 0, ndatabytes, ret, result = -1;
273*cf5a6c84SAndroid Build Coastguard Worker
274*cf5a6c84SAndroid Build Coastguard Worker sd = init_tftp(&server);
275*cf5a6c84SAndroid Build Coastguard Worker
276*cf5a6c84SAndroid Build Coastguard Worker packet = (uint8_t*) xzalloc(TFTP_IOBUFSIZE);
277*cf5a6c84SAndroid Build Coastguard Worker fd = xcreate(TT.local_file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
278*cf5a6c84SAndroid Build Coastguard Worker
279*cf5a6c84SAndroid Build Coastguard Worker len = mkpkt_request(packet, TFTP_OP_RRQ, TT.remote_file, 1);
280*cf5a6c84SAndroid Build Coastguard Worker ret = write_server(sd, packet, len, &server);
281*cf5a6c84SAndroid Build Coastguard Worker if (ret != len){
282*cf5a6c84SAndroid Build Coastguard Worker unlink(TT.local_file);
283*cf5a6c84SAndroid Build Coastguard Worker goto errout_with_sd;
284*cf5a6c84SAndroid Build Coastguard Worker }
285*cf5a6c84SAndroid Build Coastguard Worker if (TT.af == AF_INET6) ((struct sockaddr_in6 *)&server)->sin6_port = 0;
286*cf5a6c84SAndroid Build Coastguard Worker else ((struct sockaddr_in *)&server)->sin_port = 0;
287*cf5a6c84SAndroid Build Coastguard Worker
288*cf5a6c84SAndroid Build Coastguard Worker do {
289*cf5a6c84SAndroid Build Coastguard Worker blockno++;
290*cf5a6c84SAndroid Build Coastguard Worker for (retry = 0 ; retry < TFTP_RETRIES; retry++) {
291*cf5a6c84SAndroid Build Coastguard Worker nbytesrecvd = read_server(sd, packet, TFTP_IOBUFSIZE, &from);
292*cf5a6c84SAndroid Build Coastguard Worker if (nbytesrecvd > 0) {
293*cf5a6c84SAndroid Build Coastguard Worker if ( ((TT.af == AF_INET) &&
294*cf5a6c84SAndroid Build Coastguard Worker memcmp(&((struct sockaddr_in *)&server)->sin_addr,
295*cf5a6c84SAndroid Build Coastguard Worker &((struct sockaddr_in *)&from)->sin_addr,
296*cf5a6c84SAndroid Build Coastguard Worker sizeof(struct in_addr))) ||
297*cf5a6c84SAndroid Build Coastguard Worker ((TT.af == AF_INET6) &&
298*cf5a6c84SAndroid Build Coastguard Worker memcmp(&((struct sockaddr_in6 *)&server)->sin6_addr,
299*cf5a6c84SAndroid Build Coastguard Worker &((struct sockaddr_in6 *)&from)->sin6_addr,
300*cf5a6c84SAndroid Build Coastguard Worker sizeof(struct in6_addr)))) {
301*cf5a6c84SAndroid Build Coastguard Worker error_msg("Invalid address in DATA.");
302*cf5a6c84SAndroid Build Coastguard Worker retry--;
303*cf5a6c84SAndroid Build Coastguard Worker continue;
304*cf5a6c84SAndroid Build Coastguard Worker }
305*cf5a6c84SAndroid Build Coastguard Worker if ( ((TT.af == AF_INET) && ((struct sockaddr_in *)&server)->sin_port
306*cf5a6c84SAndroid Build Coastguard Worker && (((struct sockaddr_in *)&server)->sin_port !=
307*cf5a6c84SAndroid Build Coastguard Worker ((struct sockaddr_in *)&from)->sin_port)) ||
308*cf5a6c84SAndroid Build Coastguard Worker ((TT.af == AF_INET6) && ((struct sockaddr_in6 *)&server)->sin6_port
309*cf5a6c84SAndroid Build Coastguard Worker && (((struct sockaddr_in6 *)&server)->sin6_port !=
310*cf5a6c84SAndroid Build Coastguard Worker ((struct sockaddr_in6 *)&from)->sin6_port))) {
311*cf5a6c84SAndroid Build Coastguard Worker error_msg("Invalid port in DATA.");
312*cf5a6c84SAndroid Build Coastguard Worker len = mkpkt_err(packet, TFTP_ER_UNKID, TFTP_ES_UNKID);
313*cf5a6c84SAndroid Build Coastguard Worker ret = write_server(sd, packet, len, &from);
314*cf5a6c84SAndroid Build Coastguard Worker retry--;
315*cf5a6c84SAndroid Build Coastguard Worker continue;
316*cf5a6c84SAndroid Build Coastguard Worker }
317*cf5a6c84SAndroid Build Coastguard Worker if (nbytesrecvd < TFTP_DATAHEADERSIZE) {
318*cf5a6c84SAndroid Build Coastguard Worker error_msg("Tiny data packet ignored.");
319*cf5a6c84SAndroid Build Coastguard Worker continue;
320*cf5a6c84SAndroid Build Coastguard Worker }
321*cf5a6c84SAndroid Build Coastguard Worker if (check_data(packet, &opcode, &rblockno) != 0
322*cf5a6c84SAndroid Build Coastguard Worker || blockno != rblockno) {
323*cf5a6c84SAndroid Build Coastguard Worker
324*cf5a6c84SAndroid Build Coastguard Worker if (opcode == TFTP_OP_ERR) {
325*cf5a6c84SAndroid Build Coastguard Worker char *message = "DATA Check failure.";
326*cf5a6c84SAndroid Build Coastguard Worker char *arr[] = {TFTP_ES_NOSUCHFILE, TFTP_ES_ACCESS,
327*cf5a6c84SAndroid Build Coastguard Worker TFTP_ES_FULL, TFTP_ES_ILLEGALOP,
328*cf5a6c84SAndroid Build Coastguard Worker TFTP_ES_UNKID, TFTP_ES_EXISTS,
329*cf5a6c84SAndroid Build Coastguard Worker TFTP_ES_UNKUSER, TFTP_ES_NEGOTIATE};
330*cf5a6c84SAndroid Build Coastguard Worker if (rblockno && (rblockno < 9)) message = arr[rblockno - 1];
331*cf5a6c84SAndroid Build Coastguard Worker error_msg_raw(message);
332*cf5a6c84SAndroid Build Coastguard Worker }
333*cf5a6c84SAndroid Build Coastguard Worker else if (blockno == 1 && opcode == TFTP_OP_OACK) {
334*cf5a6c84SAndroid Build Coastguard Worker len = mkpkt_ack(packet, 0);
335*cf5a6c84SAndroid Build Coastguard Worker ret = write_server(sd, packet, len, &from);
336*cf5a6c84SAndroid Build Coastguard Worker if (ret != len){
337*cf5a6c84SAndroid Build Coastguard Worker unlink(TT.local_file);
338*cf5a6c84SAndroid Build Coastguard Worker goto errout_with_sd;
339*cf5a6c84SAndroid Build Coastguard Worker }
340*cf5a6c84SAndroid Build Coastguard Worker }
341*cf5a6c84SAndroid Build Coastguard Worker else if (opcode > 5) {
342*cf5a6c84SAndroid Build Coastguard Worker len = mkpkt_err(packet, TFTP_ER_ILLEGALOP, TFTP_ES_ILLEGALOP);
343*cf5a6c84SAndroid Build Coastguard Worker ret = write_server(sd, packet, len, &from);
344*cf5a6c84SAndroid Build Coastguard Worker }
345*cf5a6c84SAndroid Build Coastguard Worker continue;
346*cf5a6c84SAndroid Build Coastguard Worker }
347*cf5a6c84SAndroid Build Coastguard Worker if ((TT.af == AF_INET6) && !((struct sockaddr_in6 *)&server)->sin6_port)
348*cf5a6c84SAndroid Build Coastguard Worker ((struct sockaddr_in6 *)&server)->sin6_port =
349*cf5a6c84SAndroid Build Coastguard Worker ((struct sockaddr_in6 *)&from)->sin6_port;
350*cf5a6c84SAndroid Build Coastguard Worker else if ((TT.af == AF_INET) && !((struct sockaddr_in *)&server)->sin_port)
351*cf5a6c84SAndroid Build Coastguard Worker ((struct sockaddr_in *)&server)->sin_port =
352*cf5a6c84SAndroid Build Coastguard Worker ((struct sockaddr_in *)&from)->sin_port;
353*cf5a6c84SAndroid Build Coastguard Worker break;
354*cf5a6c84SAndroid Build Coastguard Worker }
355*cf5a6c84SAndroid Build Coastguard Worker }
356*cf5a6c84SAndroid Build Coastguard Worker if (retry == TFTP_RETRIES) {
357*cf5a6c84SAndroid Build Coastguard Worker error_msg("Retry limit exceeded.");
358*cf5a6c84SAndroid Build Coastguard Worker unlink(TT.local_file);
359*cf5a6c84SAndroid Build Coastguard Worker goto errout_with_sd;
360*cf5a6c84SAndroid Build Coastguard Worker }
361*cf5a6c84SAndroid Build Coastguard Worker ndatabytes = nbytesrecvd - TFTP_DATAHEADERSIZE;
362*cf5a6c84SAndroid Build Coastguard Worker if (writeall(fd, packet + TFTP_DATAHEADERSIZE, ndatabytes) < 0){
363*cf5a6c84SAndroid Build Coastguard Worker unlink(TT.local_file);
364*cf5a6c84SAndroid Build Coastguard Worker goto errout_with_sd;
365*cf5a6c84SAndroid Build Coastguard Worker }
366*cf5a6c84SAndroid Build Coastguard Worker len = mkpkt_ack(packet, blockno);
367*cf5a6c84SAndroid Build Coastguard Worker ret = write_server(sd, packet, len, &server);
368*cf5a6c84SAndroid Build Coastguard Worker if (ret != len){
369*cf5a6c84SAndroid Build Coastguard Worker unlink(TT.local_file);
370*cf5a6c84SAndroid Build Coastguard Worker goto errout_with_sd;
371*cf5a6c84SAndroid Build Coastguard Worker }
372*cf5a6c84SAndroid Build Coastguard Worker } while (ndatabytes >= TFTP_DATASIZE);
373*cf5a6c84SAndroid Build Coastguard Worker
374*cf5a6c84SAndroid Build Coastguard Worker result = 0;
375*cf5a6c84SAndroid Build Coastguard Worker
376*cf5a6c84SAndroid Build Coastguard Worker errout_with_sd: xclose(sd);
377*cf5a6c84SAndroid Build Coastguard Worker free(packet);
378*cf5a6c84SAndroid Build Coastguard Worker return result;
379*cf5a6c84SAndroid Build Coastguard Worker }
380*cf5a6c84SAndroid Build Coastguard Worker
381*cf5a6c84SAndroid Build Coastguard Worker // Sends file to server.
file_put(void)382*cf5a6c84SAndroid Build Coastguard Worker int file_put(void)
383*cf5a6c84SAndroid Build Coastguard Worker {
384*cf5a6c84SAndroid Build Coastguard Worker struct sockaddr_storage server;
385*cf5a6c84SAndroid Build Coastguard Worker uint8_t *packet;
386*cf5a6c84SAndroid Build Coastguard Worker off_t offset = 0;
387*cf5a6c84SAndroid Build Coastguard Worker uint16_t blockno = 1, rblockno, port = 0;
388*cf5a6c84SAndroid Build Coastguard Worker int packetlen, sd, fd, retry = 0, ret, result = -1;
389*cf5a6c84SAndroid Build Coastguard Worker
390*cf5a6c84SAndroid Build Coastguard Worker sd = init_tftp(&server);
391*cf5a6c84SAndroid Build Coastguard Worker packet = (uint8_t*)xzalloc(TFTP_IOBUFSIZE);
392*cf5a6c84SAndroid Build Coastguard Worker fd = xopenro(TT.local_file);
393*cf5a6c84SAndroid Build Coastguard Worker
394*cf5a6c84SAndroid Build Coastguard Worker for (;;) { //first loop for request send and confirmation from server.
395*cf5a6c84SAndroid Build Coastguard Worker packetlen = mkpkt_request(packet, TFTP_OP_WRQ, TT.remote_file, 1);
396*cf5a6c84SAndroid Build Coastguard Worker ret = write_server(sd, packet, packetlen, &server);
397*cf5a6c84SAndroid Build Coastguard Worker if (ret != packetlen) goto errout_with_sd;
398*cf5a6c84SAndroid Build Coastguard Worker if (read_ack(sd, packet, &server, &port, NULL) == 0) break;
399*cf5a6c84SAndroid Build Coastguard Worker if (++retry > TFTP_RETRIES) {
400*cf5a6c84SAndroid Build Coastguard Worker error_msg("Retry count exceeded.");
401*cf5a6c84SAndroid Build Coastguard Worker goto errout_with_sd;
402*cf5a6c84SAndroid Build Coastguard Worker }
403*cf5a6c84SAndroid Build Coastguard Worker }
404*cf5a6c84SAndroid Build Coastguard Worker for (;;) { // loop for data sending and receving ack from server.
405*cf5a6c84SAndroid Build Coastguard Worker packetlen = mkpkt_data(fd, offset, packet, blockno);
406*cf5a6c84SAndroid Build Coastguard Worker if (packetlen < 0) goto errout_with_sd;
407*cf5a6c84SAndroid Build Coastguard Worker
408*cf5a6c84SAndroid Build Coastguard Worker ret = write_server(sd, packet, packetlen, &server);
409*cf5a6c84SAndroid Build Coastguard Worker if (ret != packetlen) goto errout_with_sd;
410*cf5a6c84SAndroid Build Coastguard Worker
411*cf5a6c84SAndroid Build Coastguard Worker if (read_ack(sd, packet, &server, &port, &rblockno) == 0) {
412*cf5a6c84SAndroid Build Coastguard Worker if (rblockno == blockno) {
413*cf5a6c84SAndroid Build Coastguard Worker if (packetlen < TFTP_PACKETSIZE) break;
414*cf5a6c84SAndroid Build Coastguard Worker blockno++;
415*cf5a6c84SAndroid Build Coastguard Worker offset += TFTP_DATASIZE;
416*cf5a6c84SAndroid Build Coastguard Worker retry = 0;
417*cf5a6c84SAndroid Build Coastguard Worker continue;
418*cf5a6c84SAndroid Build Coastguard Worker }
419*cf5a6c84SAndroid Build Coastguard Worker }
420*cf5a6c84SAndroid Build Coastguard Worker if (++retry > TFTP_RETRIES) {
421*cf5a6c84SAndroid Build Coastguard Worker error_msg("Retry count exceeded.");
422*cf5a6c84SAndroid Build Coastguard Worker goto errout_with_sd;
423*cf5a6c84SAndroid Build Coastguard Worker }
424*cf5a6c84SAndroid Build Coastguard Worker }
425*cf5a6c84SAndroid Build Coastguard Worker result = 0;
426*cf5a6c84SAndroid Build Coastguard Worker
427*cf5a6c84SAndroid Build Coastguard Worker errout_with_sd: close(sd);
428*cf5a6c84SAndroid Build Coastguard Worker free(packet);
429*cf5a6c84SAndroid Build Coastguard Worker return result;
430*cf5a6c84SAndroid Build Coastguard Worker }
431*cf5a6c84SAndroid Build Coastguard Worker
tftp_main(void)432*cf5a6c84SAndroid Build Coastguard Worker void tftp_main(void)
433*cf5a6c84SAndroid Build Coastguard Worker {
434*cf5a6c84SAndroid Build Coastguard Worker struct addrinfo *info, rp, *res=0;
435*cf5a6c84SAndroid Build Coastguard Worker int ret;
436*cf5a6c84SAndroid Build Coastguard Worker
437*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(r)) {
438*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(l)) {
439*cf5a6c84SAndroid Build Coastguard Worker char *slash = strrchr(TT.remote_file, '/');
440*cf5a6c84SAndroid Build Coastguard Worker TT.local_file = (slash) ? slash + 1 : TT.remote_file;
441*cf5a6c84SAndroid Build Coastguard Worker }
442*cf5a6c84SAndroid Build Coastguard Worker } else if (FLAG(l)) TT.remote_file = TT.local_file;
443*cf5a6c84SAndroid Build Coastguard Worker else error_exit("Please provide some files.");
444*cf5a6c84SAndroid Build Coastguard Worker
445*cf5a6c84SAndroid Build Coastguard Worker memset(&rp, 0, sizeof(rp));
446*cf5a6c84SAndroid Build Coastguard Worker rp.ai_family = AF_UNSPEC;
447*cf5a6c84SAndroid Build Coastguard Worker rp.ai_socktype = SOCK_STREAM;
448*cf5a6c84SAndroid Build Coastguard Worker ret = getaddrinfo(toys.optargs[0], toys.optargs[1], &rp, &info);
449*cf5a6c84SAndroid Build Coastguard Worker if (!ret) {
450*cf5a6c84SAndroid Build Coastguard Worker for (res = info; res; res = res->ai_next)
451*cf5a6c84SAndroid Build Coastguard Worker if ( (res->ai_family == AF_INET) || (res->ai_family == AF_INET6)) break;
452*cf5a6c84SAndroid Build Coastguard Worker }
453*cf5a6c84SAndroid Build Coastguard Worker if (!res)
454*cf5a6c84SAndroid Build Coastguard Worker error_exit("bad address '%s' : %s", toys.optargs[0], gai_strerror(ret));
455*cf5a6c84SAndroid Build Coastguard Worker TT.af = info->ai_family;
456*cf5a6c84SAndroid Build Coastguard Worker
457*cf5a6c84SAndroid Build Coastguard Worker memcpy((void *)&TT.inaddr, info->ai_addr, info->ai_addrlen);
458*cf5a6c84SAndroid Build Coastguard Worker freeaddrinfo(info);
459*cf5a6c84SAndroid Build Coastguard Worker
460*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(g)) file_get();
461*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(p)) file_put();
462*cf5a6c84SAndroid Build Coastguard Worker }
463