1*479ab7f0SSascha Wildner /* $NetBSD: tftp.c,v 1.4 1997/09/17 16:57:07 drochner Exp $ */
2*479ab7f0SSascha Wildner
3*479ab7f0SSascha Wildner /*
4*479ab7f0SSascha Wildner * Copyright (c) 1996
5*479ab7f0SSascha Wildner * Matthias Drochner. All rights reserved.
6*479ab7f0SSascha Wildner *
7*479ab7f0SSascha Wildner * Redistribution and use in source and binary forms, with or without
8*479ab7f0SSascha Wildner * modification, are permitted provided that the following conditions
9*479ab7f0SSascha Wildner * are met:
10*479ab7f0SSascha Wildner * 1. Redistributions of source code must retain the above copyright
11*479ab7f0SSascha Wildner * notice, this list of conditions and the following disclaimer.
12*479ab7f0SSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright
13*479ab7f0SSascha Wildner * notice, this list of conditions and the following disclaimer in the
14*479ab7f0SSascha Wildner * documentation and/or other materials provided with the distribution.
15*479ab7f0SSascha Wildner * 3. All advertising materials mentioning features or use of this software
16*479ab7f0SSascha Wildner * must display the following acknowledgement:
17*479ab7f0SSascha Wildner * This product includes software developed for the NetBSD Project
18*479ab7f0SSascha Wildner * by Matthias Drochner.
19*479ab7f0SSascha Wildner * 4. The name of the author may not be used to endorse or promote products
20*479ab7f0SSascha Wildner * derived from this software without specific prior written permission.
21*479ab7f0SSascha Wildner *
22*479ab7f0SSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23*479ab7f0SSascha Wildner * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24*479ab7f0SSascha Wildner * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25*479ab7f0SSascha Wildner * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26*479ab7f0SSascha Wildner * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27*479ab7f0SSascha Wildner * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28*479ab7f0SSascha Wildner * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29*479ab7f0SSascha Wildner * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30*479ab7f0SSascha Wildner * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31*479ab7f0SSascha Wildner * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32*479ab7f0SSascha Wildner *
33*479ab7f0SSascha Wildner * $FreeBSD: src/lib/libstand/tftp.c,v 1.2.6.4 2001/07/14 14:00:03 mikeh Exp $
34*479ab7f0SSascha Wildner */
35*479ab7f0SSascha Wildner
36*479ab7f0SSascha Wildner /*
37*479ab7f0SSascha Wildner * Simple TFTP implementation for libsa.
38*479ab7f0SSascha Wildner * Assumes:
39*479ab7f0SSascha Wildner * - socket descriptor (int) at open_file->f_devdata
40*479ab7f0SSascha Wildner * - server host IP in global servip
41*479ab7f0SSascha Wildner * Restrictions:
42*479ab7f0SSascha Wildner * - read only
43*479ab7f0SSascha Wildner * - lseek only with SEEK_SET or SEEK_CUR
44*479ab7f0SSascha Wildner * - no big time differences between transfers (<tftp timeout)
45*479ab7f0SSascha Wildner */
46*479ab7f0SSascha Wildner
47*479ab7f0SSascha Wildner #include <sys/param.h>
48*479ab7f0SSascha Wildner #include <sys/stat.h>
49*479ab7f0SSascha Wildner #include <netinet/in.h>
50*479ab7f0SSascha Wildner #include <netinet/udp.h>
51*479ab7f0SSascha Wildner #include <netinet/ip.h>
52*479ab7f0SSascha Wildner #include <netinet/in_systm.h>
53*479ab7f0SSascha Wildner #include <arpa/tftp.h>
54*479ab7f0SSascha Wildner
55*479ab7f0SSascha Wildner #include <string.h>
56*479ab7f0SSascha Wildner
57*479ab7f0SSascha Wildner #include "stand.h"
58*479ab7f0SSascha Wildner #include "net.h"
59*479ab7f0SSascha Wildner #include "netif.h"
60*479ab7f0SSascha Wildner
61*479ab7f0SSascha Wildner #include "tftp.h"
62*479ab7f0SSascha Wildner
63*479ab7f0SSascha Wildner static int tftp_open(const char *path, struct open_file *f);
64*479ab7f0SSascha Wildner static int tftp_close(struct open_file *f);
65*479ab7f0SSascha Wildner static int tftp_read(struct open_file *f, void *buf, size_t size, size_t *resid);
66*479ab7f0SSascha Wildner static int tftp_write(struct open_file *f, void *buf, size_t size, size_t *resid);
67*479ab7f0SSascha Wildner static off_t tftp_seek(struct open_file *f, off_t offset, int where);
68*479ab7f0SSascha Wildner static int tftp_stat(struct open_file *f, struct stat *sb);
69*479ab7f0SSascha Wildner
70*479ab7f0SSascha Wildner struct fs_ops tftp_fsops = {
71*479ab7f0SSascha Wildner "tftp",
72*479ab7f0SSascha Wildner tftp_open,
73*479ab7f0SSascha Wildner tftp_close,
74*479ab7f0SSascha Wildner tftp_read,
75*479ab7f0SSascha Wildner tftp_write,
76*479ab7f0SSascha Wildner tftp_seek,
77*479ab7f0SSascha Wildner tftp_stat,
78*479ab7f0SSascha Wildner null_readdir
79*479ab7f0SSascha Wildner };
80*479ab7f0SSascha Wildner
81*479ab7f0SSascha Wildner extern struct in_addr servip;
82*479ab7f0SSascha Wildner
83*479ab7f0SSascha Wildner static int tftpport = 2000;
84*479ab7f0SSascha Wildner
85*479ab7f0SSascha Wildner #define RSPACE 520 /* max data packet, rounded up */
86*479ab7f0SSascha Wildner
87*479ab7f0SSascha Wildner struct tftp_handle {
88*479ab7f0SSascha Wildner struct iodesc *iodesc;
89*479ab7f0SSascha Wildner int currblock; /* contents of lastdata */
90*479ab7f0SSascha Wildner int islastblock; /* flag */
91*479ab7f0SSascha Wildner int validsize;
92*479ab7f0SSascha Wildner int off;
93*479ab7f0SSascha Wildner char *path; /* saved for re-requests */
94*479ab7f0SSascha Wildner struct {
95*479ab7f0SSascha Wildner u_char header[HEADER_SIZE];
96*479ab7f0SSascha Wildner struct tftphdr t;
97*479ab7f0SSascha Wildner u_char space[RSPACE];
98*479ab7f0SSascha Wildner } __packed __aligned(4) lastdata;
99*479ab7f0SSascha Wildner };
100*479ab7f0SSascha Wildner
101*479ab7f0SSascha Wildner static int tftperrors[8] = {
102*479ab7f0SSascha Wildner 0, /* ??? */
103*479ab7f0SSascha Wildner ENOENT,
104*479ab7f0SSascha Wildner EPERM,
105*479ab7f0SSascha Wildner ENOSPC,
106*479ab7f0SSascha Wildner EINVAL, /* ??? */
107*479ab7f0SSascha Wildner EINVAL, /* ??? */
108*479ab7f0SSascha Wildner EEXIST,
109*479ab7f0SSascha Wildner EINVAL /* ??? */
110*479ab7f0SSascha Wildner };
111*479ab7f0SSascha Wildner
112*479ab7f0SSascha Wildner static ssize_t
recvtftp(struct iodesc * d,void * pkt,size_t max_len,time_t tleft)113*479ab7f0SSascha Wildner recvtftp(struct iodesc *d, void *pkt, size_t max_len, time_t tleft)
114*479ab7f0SSascha Wildner {
115*479ab7f0SSascha Wildner struct tftphdr *t;
116*479ab7f0SSascha Wildner ssize_t len;
117*479ab7f0SSascha Wildner ssize_t tmp_len;
118*479ab7f0SSascha Wildner
119*479ab7f0SSascha Wildner /*
120*479ab7f0SSascha Wildner * Note: errno of 0 with -1 return means udp poll failed or
121*479ab7f0SSascha Wildner * packet was not for us.
122*479ab7f0SSascha Wildner *
123*479ab7f0SSascha Wildner * We may end up broadcasting the initial TFTP request. Take the
124*479ab7f0SSascha Wildner * first DATA result and save any ERROR result in case we do not
125*479ab7f0SSascha Wildner * get a DATA.
126*479ab7f0SSascha Wildner */
127*479ab7f0SSascha Wildner errno = 0;
128*479ab7f0SSascha Wildner bzero(pkt, max_len);
129*479ab7f0SSascha Wildner if (d->xid == 1) {
130*479ab7f0SSascha Wildner len = -1;
131*479ab7f0SSascha Wildner while ((tmp_len = readudp(d, pkt, max_len, tleft)) > 0) {
132*479ab7f0SSascha Wildner len = tmp_len;
133*479ab7f0SSascha Wildner t = (struct tftphdr *)pkt;
134*479ab7f0SSascha Wildner if (ntohs(t->th_opcode) == DATA)
135*479ab7f0SSascha Wildner break;
136*479ab7f0SSascha Wildner }
137*479ab7f0SSascha Wildner } else {
138*479ab7f0SSascha Wildner len = readudp(d, pkt, max_len, tleft);
139*479ab7f0SSascha Wildner }
140*479ab7f0SSascha Wildner if ((int)len < (int)sizeof(*t))
141*479ab7f0SSascha Wildner return (-1);
142*479ab7f0SSascha Wildner t = (struct tftphdr *)pkt;
143*479ab7f0SSascha Wildner errno = 0;
144*479ab7f0SSascha Wildner
145*479ab7f0SSascha Wildner switch (ntohs(t->th_opcode)) {
146*479ab7f0SSascha Wildner case DATA: {
147*479ab7f0SSascha Wildner int got;
148*479ab7f0SSascha Wildner
149*479ab7f0SSascha Wildner if (htons(t->th_block) != (uint16_t)d->xid) {
150*479ab7f0SSascha Wildner /*
151*479ab7f0SSascha Wildner * Expected block?
152*479ab7f0SSascha Wildner */
153*479ab7f0SSascha Wildner return (-1);
154*479ab7f0SSascha Wildner }
155*479ab7f0SSascha Wildner if (d->xid == 1) {
156*479ab7f0SSascha Wildner /*
157*479ab7f0SSascha Wildner * First data packet from new port. Set destip in
158*479ab7f0SSascha Wildner * case we got replies from multiple hosts, so only
159*479ab7f0SSascha Wildner * one host is selected.
160*479ab7f0SSascha Wildner */
161*479ab7f0SSascha Wildner struct udphdr *uh;
162*479ab7f0SSascha Wildner struct ip *ip;
163*479ab7f0SSascha Wildner
164*479ab7f0SSascha Wildner uh = (struct udphdr *) pkt - 1;
165*479ab7f0SSascha Wildner ip = (struct ip *)uh - 1;
166*479ab7f0SSascha Wildner d->destport = uh->uh_sport;
167*479ab7f0SSascha Wildner d->destip = ip->ip_src;
168*479ab7f0SSascha Wildner } /* else check uh_sport has not changed??? */
169*479ab7f0SSascha Wildner got = len - (t->th_data - (char *)t);
170*479ab7f0SSascha Wildner return got;
171*479ab7f0SSascha Wildner }
172*479ab7f0SSascha Wildner case ERROR:
173*479ab7f0SSascha Wildner if ((unsigned) ntohs(t->th_code) >= 8) {
174*479ab7f0SSascha Wildner printf("illegal tftp error %d\n", ntohs(t->th_code));
175*479ab7f0SSascha Wildner errno = EIO;
176*479ab7f0SSascha Wildner } else {
177*479ab7f0SSascha Wildner #ifdef DEBUG
178*479ab7f0SSascha Wildner printf("tftp-error %d\n", ntohs(t->th_code));
179*479ab7f0SSascha Wildner #endif
180*479ab7f0SSascha Wildner errno = tftperrors[ntohs(t->th_code)];
181*479ab7f0SSascha Wildner }
182*479ab7f0SSascha Wildner return (-1);
183*479ab7f0SSascha Wildner default:
184*479ab7f0SSascha Wildner #ifdef DEBUG
185*479ab7f0SSascha Wildner printf("tftp type %d not handled\n", ntohs(t->th_opcode));
186*479ab7f0SSascha Wildner #endif
187*479ab7f0SSascha Wildner return (-1);
188*479ab7f0SSascha Wildner }
189*479ab7f0SSascha Wildner }
190*479ab7f0SSascha Wildner
191*479ab7f0SSascha Wildner /* send request, expect first block (or error) */
192*479ab7f0SSascha Wildner static int
tftp_makereq(struct tftp_handle * h)193*479ab7f0SSascha Wildner tftp_makereq(struct tftp_handle *h)
194*479ab7f0SSascha Wildner {
195*479ab7f0SSascha Wildner struct {
196*479ab7f0SSascha Wildner u_char header[HEADER_SIZE];
197*479ab7f0SSascha Wildner struct tftphdr t;
198*479ab7f0SSascha Wildner u_char space[FNAME_SIZE + 6];
199*479ab7f0SSascha Wildner } __packed __aligned(4) wbuf;
200*479ab7f0SSascha Wildner char *wtail;
201*479ab7f0SSascha Wildner int l;
202*479ab7f0SSascha Wildner ssize_t res;
203*479ab7f0SSascha Wildner struct tftphdr *t;
204*479ab7f0SSascha Wildner
205*479ab7f0SSascha Wildner wbuf.t.th_opcode = htons((u_short) RRQ);
206*479ab7f0SSascha Wildner wtail = wbuf.t.th_stuff;
207*479ab7f0SSascha Wildner l = strlen(h->path);
208*479ab7f0SSascha Wildner bcopy(h->path, wtail, l + 1);
209*479ab7f0SSascha Wildner wtail += l + 1;
210*479ab7f0SSascha Wildner bcopy("octet", wtail, 6);
211*479ab7f0SSascha Wildner wtail += 6;
212*479ab7f0SSascha Wildner
213*479ab7f0SSascha Wildner t = &h->lastdata.t;
214*479ab7f0SSascha Wildner
215*479ab7f0SSascha Wildner /* h->iodesc->myport = htons(--tftpport); */
216*479ab7f0SSascha Wildner h->iodesc->myport = htons(tftpport + (getsecs() & 0x3ff));
217*479ab7f0SSascha Wildner h->iodesc->destport = htons(IPPORT_TFTP);
218*479ab7f0SSascha Wildner h->iodesc->xid = 1; /* expected block */
219*479ab7f0SSascha Wildner
220*479ab7f0SSascha Wildner res = sendrecv(h->iodesc, sendudp, &wbuf.t, wtail - (char *) &wbuf.t,
221*479ab7f0SSascha Wildner recvtftp, t, sizeof(*t) + RSPACE);
222*479ab7f0SSascha Wildner
223*479ab7f0SSascha Wildner if (res == -1)
224*479ab7f0SSascha Wildner return (errno);
225*479ab7f0SSascha Wildner
226*479ab7f0SSascha Wildner h->currblock = 1;
227*479ab7f0SSascha Wildner h->validsize = res;
228*479ab7f0SSascha Wildner h->islastblock = 0;
229*479ab7f0SSascha Wildner if (res < SEGSIZE)
230*479ab7f0SSascha Wildner h->islastblock = 1; /* very short file */
231*479ab7f0SSascha Wildner return (0);
232*479ab7f0SSascha Wildner }
233*479ab7f0SSascha Wildner
234*479ab7f0SSascha Wildner /* ack block, expect next */
235*479ab7f0SSascha Wildner static int
tftp_getnextblock(struct tftp_handle * h)236*479ab7f0SSascha Wildner tftp_getnextblock(struct tftp_handle *h)
237*479ab7f0SSascha Wildner {
238*479ab7f0SSascha Wildner struct {
239*479ab7f0SSascha Wildner u_char header[HEADER_SIZE];
240*479ab7f0SSascha Wildner struct tftphdr t;
241*479ab7f0SSascha Wildner } __packed __aligned(4) wbuf;
242*479ab7f0SSascha Wildner char *wtail;
243*479ab7f0SSascha Wildner int res;
244*479ab7f0SSascha Wildner struct tftphdr *t;
245*479ab7f0SSascha Wildner
246*479ab7f0SSascha Wildner /*
247*479ab7f0SSascha Wildner * Ack previous block
248*479ab7f0SSascha Wildner */
249*479ab7f0SSascha Wildner wbuf.t.th_opcode = htons((u_short) ACK);
250*479ab7f0SSascha Wildner wtail = (char *) &wbuf.t.th_block;
251*479ab7f0SSascha Wildner wbuf.t.th_block = htons((u_short) h->currblock);
252*479ab7f0SSascha Wildner wtail += 2;
253*479ab7f0SSascha Wildner
254*479ab7f0SSascha Wildner t = &h->lastdata.t;
255*479ab7f0SSascha Wildner
256*479ab7f0SSascha Wildner h->iodesc->xid = h->currblock + 1; /* expected block */
257*479ab7f0SSascha Wildner
258*479ab7f0SSascha Wildner res = sendrecv(h->iodesc, sendudp, &wbuf.t, wtail - (char *) &wbuf.t,
259*479ab7f0SSascha Wildner recvtftp, t, sizeof(*t) + RSPACE);
260*479ab7f0SSascha Wildner
261*479ab7f0SSascha Wildner if (res == -1) /* 0 is OK! */
262*479ab7f0SSascha Wildner return (errno);
263*479ab7f0SSascha Wildner
264*479ab7f0SSascha Wildner h->currblock++;
265*479ab7f0SSascha Wildner h->validsize = res;
266*479ab7f0SSascha Wildner if (res < SEGSIZE)
267*479ab7f0SSascha Wildner h->islastblock = 1; /* EOF */
268*479ab7f0SSascha Wildner return (0);
269*479ab7f0SSascha Wildner }
270*479ab7f0SSascha Wildner
271*479ab7f0SSascha Wildner static int
tftp_open(const char * path,struct open_file * f)272*479ab7f0SSascha Wildner tftp_open(const char *path, struct open_file *f)
273*479ab7f0SSascha Wildner {
274*479ab7f0SSascha Wildner struct tftp_handle *tftpfile;
275*479ab7f0SSascha Wildner struct iodesc *io;
276*479ab7f0SSascha Wildner int res;
277*479ab7f0SSascha Wildner
278*479ab7f0SSascha Wildner /* Avoid trying out tftp_open for disk devices in the EFI loader */
279*479ab7f0SSascha Wildner #ifndef __i386__
280*479ab7f0SSascha Wildner if (strcmp(f->f_dev->dv_name, "net") != 0)
281*479ab7f0SSascha Wildner return (EINVAL);
282*479ab7f0SSascha Wildner #endif
283*479ab7f0SSascha Wildner
284*479ab7f0SSascha Wildner tftpfile = (struct tftp_handle *) malloc(sizeof(*tftpfile));
285*479ab7f0SSascha Wildner if (!tftpfile)
286*479ab7f0SSascha Wildner return (ENOMEM);
287*479ab7f0SSascha Wildner
288*479ab7f0SSascha Wildner tftpfile->iodesc = io = socktodesc(*(int *) (f->f_devdata));
289*479ab7f0SSascha Wildner if (io == NULL) {
290*479ab7f0SSascha Wildner free(tftpfile);
291*479ab7f0SSascha Wildner return (EINVAL);
292*479ab7f0SSascha Wildner }
293*479ab7f0SSascha Wildner
294*479ab7f0SSascha Wildner io->destip = servip;
295*479ab7f0SSascha Wildner tftpfile->off = 0;
296*479ab7f0SSascha Wildner tftpfile->path = strdup(path);
297*479ab7f0SSascha Wildner if (tftpfile->path == NULL) {
298*479ab7f0SSascha Wildner free(tftpfile);
299*479ab7f0SSascha Wildner return(ENOMEM);
300*479ab7f0SSascha Wildner }
301*479ab7f0SSascha Wildner
302*479ab7f0SSascha Wildner res = tftp_makereq(tftpfile);
303*479ab7f0SSascha Wildner
304*479ab7f0SSascha Wildner if (res) {
305*479ab7f0SSascha Wildner free(tftpfile->path);
306*479ab7f0SSascha Wildner free(tftpfile);
307*479ab7f0SSascha Wildner return (res);
308*479ab7f0SSascha Wildner }
309*479ab7f0SSascha Wildner f->f_fsdata = (void *) tftpfile;
310*479ab7f0SSascha Wildner return (0);
311*479ab7f0SSascha Wildner }
312*479ab7f0SSascha Wildner
313*479ab7f0SSascha Wildner /*
314*479ab7f0SSascha Wildner * Parameters:
315*479ab7f0SSascha Wildner * resid: out
316*479ab7f0SSascha Wildner */
317*479ab7f0SSascha Wildner static int
tftp_read(struct open_file * f,void * addr,size_t size,size_t * resid)318*479ab7f0SSascha Wildner tftp_read(struct open_file *f, void *addr, size_t size, size_t *resid)
319*479ab7f0SSascha Wildner {
320*479ab7f0SSascha Wildner struct tftp_handle *tftpfile;
321*479ab7f0SSascha Wildner static int tc = 0;
322*479ab7f0SSascha Wildner tftpfile = (struct tftp_handle *) f->f_fsdata;
323*479ab7f0SSascha Wildner
324*479ab7f0SSascha Wildner while (size > 0) {
325*479ab7f0SSascha Wildner int needblock, count;
326*479ab7f0SSascha Wildner
327*479ab7f0SSascha Wildner if (!(tc++ % 256))
328*479ab7f0SSascha Wildner twiddle();
329*479ab7f0SSascha Wildner
330*479ab7f0SSascha Wildner needblock = tftpfile->off / SEGSIZE + 1;
331*479ab7f0SSascha Wildner
332*479ab7f0SSascha Wildner if (tftpfile->currblock > needblock) /* seek backwards */
333*479ab7f0SSascha Wildner tftp_makereq(tftpfile); /* no error check, it worked
334*479ab7f0SSascha Wildner * for open */
335*479ab7f0SSascha Wildner
336*479ab7f0SSascha Wildner while (tftpfile->currblock < needblock) {
337*479ab7f0SSascha Wildner int res;
338*479ab7f0SSascha Wildner
339*479ab7f0SSascha Wildner res = tftp_getnextblock(tftpfile);
340*479ab7f0SSascha Wildner if (res) { /* no answer */
341*479ab7f0SSascha Wildner #ifdef DEBUG
342*479ab7f0SSascha Wildner printf("tftp: read error\n");
343*479ab7f0SSascha Wildner #endif
344*479ab7f0SSascha Wildner return (res);
345*479ab7f0SSascha Wildner }
346*479ab7f0SSascha Wildner if (tftpfile->islastblock)
347*479ab7f0SSascha Wildner break;
348*479ab7f0SSascha Wildner }
349*479ab7f0SSascha Wildner
350*479ab7f0SSascha Wildner if (tftpfile->currblock == needblock) {
351*479ab7f0SSascha Wildner int offinblock, inbuffer;
352*479ab7f0SSascha Wildner
353*479ab7f0SSascha Wildner offinblock = tftpfile->off % SEGSIZE;
354*479ab7f0SSascha Wildner
355*479ab7f0SSascha Wildner inbuffer = tftpfile->validsize - offinblock;
356*479ab7f0SSascha Wildner if (inbuffer < 0) {
357*479ab7f0SSascha Wildner #ifdef DEBUG
358*479ab7f0SSascha Wildner printf("tftp: invalid offset %d\n",
359*479ab7f0SSascha Wildner tftpfile->off);
360*479ab7f0SSascha Wildner #endif
361*479ab7f0SSascha Wildner return (EINVAL);
362*479ab7f0SSascha Wildner }
363*479ab7f0SSascha Wildner count = (size < inbuffer ? size : inbuffer);
364*479ab7f0SSascha Wildner bcopy(tftpfile->lastdata.t.th_data + offinblock,
365*479ab7f0SSascha Wildner addr, count);
366*479ab7f0SSascha Wildner
367*479ab7f0SSascha Wildner addr = (char *)addr + count;
368*479ab7f0SSascha Wildner tftpfile->off += count;
369*479ab7f0SSascha Wildner size -= count;
370*479ab7f0SSascha Wildner
371*479ab7f0SSascha Wildner if ((tftpfile->islastblock) && (count == inbuffer))
372*479ab7f0SSascha Wildner break; /* EOF */
373*479ab7f0SSascha Wildner } else {
374*479ab7f0SSascha Wildner #ifdef DEBUG
375*479ab7f0SSascha Wildner printf("tftp: block %d not found\n", needblock);
376*479ab7f0SSascha Wildner #endif
377*479ab7f0SSascha Wildner return (EINVAL);
378*479ab7f0SSascha Wildner }
379*479ab7f0SSascha Wildner
380*479ab7f0SSascha Wildner }
381*479ab7f0SSascha Wildner
382*479ab7f0SSascha Wildner if (resid)
383*479ab7f0SSascha Wildner *resid = size;
384*479ab7f0SSascha Wildner return (0);
385*479ab7f0SSascha Wildner }
386*479ab7f0SSascha Wildner
387*479ab7f0SSascha Wildner static int
tftp_close(struct open_file * f)388*479ab7f0SSascha Wildner tftp_close(struct open_file *f)
389*479ab7f0SSascha Wildner {
390*479ab7f0SSascha Wildner struct tftp_handle *tftpfile;
391*479ab7f0SSascha Wildner tftpfile = (struct tftp_handle *) f->f_fsdata;
392*479ab7f0SSascha Wildner
393*479ab7f0SSascha Wildner /* let it time out ... */
394*479ab7f0SSascha Wildner f->f_fsdata = NULL;
395*479ab7f0SSascha Wildner if (tftpfile) {
396*479ab7f0SSascha Wildner free(tftpfile->path);
397*479ab7f0SSascha Wildner free(tftpfile);
398*479ab7f0SSascha Wildner f->f_fsdata = NULL;
399*479ab7f0SSascha Wildner }
400*479ab7f0SSascha Wildner return (0);
401*479ab7f0SSascha Wildner }
402*479ab7f0SSascha Wildner
403*479ab7f0SSascha Wildner /*
404*479ab7f0SSascha Wildner * Parameters:
405*479ab7f0SSascha Wildner * resid: out
406*479ab7f0SSascha Wildner */
407*479ab7f0SSascha Wildner static int
tftp_write(struct open_file * f,void * start,size_t size,size_t * resid)408*479ab7f0SSascha Wildner tftp_write(struct open_file *f, void *start, size_t size, size_t *resid)
409*479ab7f0SSascha Wildner {
410*479ab7f0SSascha Wildner return (EROFS);
411*479ab7f0SSascha Wildner }
412*479ab7f0SSascha Wildner
413*479ab7f0SSascha Wildner static int
tftp_stat(struct open_file * f,struct stat * sb)414*479ab7f0SSascha Wildner tftp_stat(struct open_file *f, struct stat *sb)
415*479ab7f0SSascha Wildner {
416*479ab7f0SSascha Wildner sb->st_mode = 0444 | S_IFREG;
417*479ab7f0SSascha Wildner sb->st_nlink = 1;
418*479ab7f0SSascha Wildner sb->st_uid = 0;
419*479ab7f0SSascha Wildner sb->st_gid = 0;
420*479ab7f0SSascha Wildner sb->st_size = -1;
421*479ab7f0SSascha Wildner return (0);
422*479ab7f0SSascha Wildner }
423*479ab7f0SSascha Wildner
424*479ab7f0SSascha Wildner static off_t
tftp_seek(struct open_file * f,off_t offset,int where)425*479ab7f0SSascha Wildner tftp_seek(struct open_file *f, off_t offset, int where)
426*479ab7f0SSascha Wildner {
427*479ab7f0SSascha Wildner struct tftp_handle *tftpfile;
428*479ab7f0SSascha Wildner tftpfile = (struct tftp_handle *) f->f_fsdata;
429*479ab7f0SSascha Wildner
430*479ab7f0SSascha Wildner switch (where) {
431*479ab7f0SSascha Wildner case SEEK_SET:
432*479ab7f0SSascha Wildner tftpfile->off = offset;
433*479ab7f0SSascha Wildner break;
434*479ab7f0SSascha Wildner case SEEK_CUR:
435*479ab7f0SSascha Wildner tftpfile->off += offset;
436*479ab7f0SSascha Wildner break;
437*479ab7f0SSascha Wildner default:
438*479ab7f0SSascha Wildner errno = EOFFSET;
439*479ab7f0SSascha Wildner return (-1);
440*479ab7f0SSascha Wildner }
441*479ab7f0SSascha Wildner return (tftpfile->off);
442*479ab7f0SSascha Wildner }
443