/* send request, expect first block (or error) */ static int tftp_makereq(struct tftp_handle *h) { struct { u_char header[HEADER_SIZE]; struct tftphdr t; u_char space[FNAME_SIZE + 6]; } __packed __aligned(4) wbuf; char *wtail; int l; ssize_t res; struct tftphdr *t; char *tftp_blksize = NULL; int blksize_l; unsigned short rtype = 0; /* * Allow overriding default TFTP block size by setting * a tftp.blksize environment variable. */ if ((tftp_blksize = getenv("tftp.blksize")) != NULL) { tftp_set_blksize(h, tftp_blksize); } wbuf.t.th_opcode = htons((u_short) RRQ); wtail = wbuf.t.th_stuff; l = strlen(h->path); #ifdef TFTP_PREPEND_PATH if (l > FNAME_SIZE - (sizeof(TFTP_PREPEND_PATH) - 1)) return (ENAMETOOLONG); bcopy(TFTP_PREPEND_PATH, wtail, sizeof(TFTP_PREPEND_PATH) - 1); wtail += sizeof(TFTP_PREPEND_PATH) - 1; #else if (l > FNAME_SIZE) return (ENAMETOOLONG); #endif bcopy(h->path, wtail, l + 1); wtail += l + 1; bcopy("octet", wtail, 6); wtail += 6; bcopy("blksize", wtail, 8); wtail += 8; blksize_l = sprintf(wtail, "%d", h->tftp_blksize); wtail += blksize_l + 1; bcopy("tsize", wtail, 6); wtail += 6; bcopy("0", wtail, 2); wtail += 2; t = &h->lastdata.t; /* h->iodesc->myport = htons(--tftpport); */ h->iodesc->myport = htons(tftpport + (getsecs() & 0x3ff)); h->iodesc->destport = htons(IPPORT_TFTP); h->iodesc->xid = 1; /* expected block */ h->currblock = 0; h->islastblock = 0; h->validsize = 0; res = sendrecv_tftp(h, &sendudp, &wbuf.t, wtail - (char *) &wbuf.t, &recvtftp, t, sizeof(*t) + h->tftp_blksize, &rtype); if (rtype == OACK) return (tftp_getnextblock(h)); /* Server ignored our blksize request, revert to TFTP default. */ h->tftp_blksize = SEGSIZE; switch (rtype) { case DATA: { h->currblock = 1; h->validsize = res; h->islastblock = 0; if (res < h->tftp_blksize) { h->islastblock = 1; /* very short file */ tftp_sendack(h); } return (0); } case ERROR: default: return (errno); } }
static int tftp_read(struct open_file *f, void *addr, size_t size, size_t *resid /* out */) { struct tftp_handle *tftpfile; static int tc = 0; tftpfile = (struct tftp_handle *) f->f_fsdata; while (size > 0) { int needblock, count; if (!(tc++ % 16)) twiddle(); needblock = tftpfile->off / tftpfile->tftp_blksize + 1; if (tftpfile->currblock > needblock) { /* seek backwards */ tftp_senderr(tftpfile, 0, "No error: read aborted"); tftp_makereq(tftpfile); /* no error check, it worked * for open */ } while (tftpfile->currblock < needblock) { int res; res = tftp_getnextblock(tftpfile); if (res) { /* no answer */ #ifdef TFTP_DEBUG printf("tftp: read error\n"); #endif return (res); } if (tftpfile->islastblock) break; } if (tftpfile->currblock == needblock) { int offinblock, inbuffer; offinblock = tftpfile->off % tftpfile->tftp_blksize; inbuffer = tftpfile->validsize - offinblock; if (inbuffer < 0) { #ifdef TFTP_DEBUG printf("tftp: invalid offset %d\n", tftpfile->off); #endif return (EINVAL); } count = (size < inbuffer ? size : inbuffer); bcopy(tftpfile->lastdata.t.th_data + offinblock, addr, count); addr = (char *)addr + count; tftpfile->off += count; size -= count; if ((tftpfile->islastblock) && (count == inbuffer)) break; /* EOF */ } else { #ifdef TFTP_DEBUG printf("tftp: block %d not found\n", needblock); #endif return (EINVAL); } } if (resid) *resid = size; return (0); }
int tftp_read(struct open_file *f, void *addr, size_t size, size_t *resid) { struct tftp_handle *tftpfile; #if !defined(LIBSA_NO_TWIDDLE) static int tc = 0; #endif tftpfile = (struct tftp_handle *) f->f_fsdata; while (size > 0) { int needblock; size_t count; needblock = tftpfile->off / SEGSIZE + 1; if (tftpfile->currblock > needblock) { /* seek backwards */ #ifndef TFTP_NOTERMINATE tftp_terminate(tftpfile); #endif /* Don't bother to check retval: it worked for open() */ tftp_makereq(tftpfile); } while (tftpfile->currblock < needblock) { int res; #if !defined(LIBSA_NO_TWIDDLE) if ((tc++ % 16) == 0) twiddle(); #endif res = tftp_getnextblock(tftpfile); if (res) { /* no answer */ #ifdef DEBUG printf("tftp: read error (block %d->%d)\n", tftpfile->currblock, needblock); #endif return res; } if (tftpfile->islastblock) break; } if (tftpfile->currblock == needblock) { size_t offinblock, inbuffer; offinblock = tftpfile->off % SEGSIZE; inbuffer = tftpfile->validsize - offinblock; if (inbuffer < 0) { #ifdef DEBUG printf("tftp: invalid offset %d\n", tftpfile->off); #endif return EINVAL; } count = (size < inbuffer ? size : inbuffer); bcopy(tftpfile->lastdata.t.th_data + offinblock, addr, count); addr = (caddr_t)addr + count; tftpfile->off += count; size -= count; if ((tftpfile->islastblock) && (count == inbuffer)) break; /* EOF */ } else { #ifdef DEBUG printf("tftp: block %d not found\n", needblock); #endif return EINVAL; } } if (resid != NULL) *resid = size; return 0; }