PageRenderTime 40ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/avm2_env/usr/src/lib/libstand/tftp.c

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