Warning, cross-references for /kernel/fs/tftp/fsys_tftp.c need to be fixed.
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020 #include "lwip/ip.h"
0021 #include "lwip/netif.h"
0022 #include "lwip/udp.h"
0023 #include "fs/filesys.h"
0024 #include "mem/virtual.h"
0025 #include "mem/physical.h"
0026 #include "kernel.h"
0027 #include "util/debug.h"
0028 #include "util/circular.h"
0029
0030 #define DEBUG_TFTP
0031
0032 #define TFTP_PORT 69
0033 #define TFTP_BLOCK_SIZE 512
0034 #define BLOCKS_PER_NODE 7
0035 #define TFTP_RING_LEN 4
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046 enum {
0047 TFTP_OP_RRQ=1,
0048 TFTP_OP_WRQ,
0049 TFTP_OP_DATA,
0050 TFTP_OP_ACK,
0051 TFTP_OP_ERR
0052 };
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082 #ifdef DEBUG_TFTP
0083 #define DLOG(fmt,...) DLOG_PREFIX("tftp",fmt,##__VA_ARGS__)
0084 #else
0085 #define DLOG(fmt,...) ;
0086 #endif
0087
0088 static struct netif *server_if;
0089 static struct ip_addr server_ip;
0090 static uint16 server_port = TFTP_PORT;
0091 static struct udp_pcb *pcb;
0092 static struct pbuf *incoming_buf[TFTP_RING_LEN];
0093 static circular incoming;
0094
0095 struct _blocklist {
0096 struct _blocklist *next;
0097 uint32 len, start;
0098 uint8 blocks[TFTP_BLOCK_SIZE * BLOCKS_PER_NODE];
0099 };
0100 typedef struct _blocklist blocklist_t;
0101
0102 blocklist_t *curbuf, *curend;
0103
0104
0105 static int
0106 format_rrq (uint8 *buf, int len, const char *filename)
0107 {
0108 int filename_len = strlen (filename);
0109 if (2+filename_len+1+6 > len)
0110 return 0;
0111 memset (buf, 0, len);
0112 buf[1] = TFTP_OP_RRQ;
0113 memcpy (buf+2, filename, filename_len);
0114 buf[2+filename_len] = 0;
0115 memcpy (buf+2+filename_len+1, "octet\0", 6);
0116 return 2+filename_len+1+6;
0117 }
0118
0119 static int
0120 send (uint8 *buf, uint32 len)
0121 {
0122 struct pbuf *p;
0123
0124
0125 server_ip.addr = server_if->gw.addr;
0126 if (server_ip.addr == 0) {
0127 DLOG ("no server_ip");
0128 return -1;
0129 }
0130
0131 p = pbuf_alloc (PBUF_TRANSPORT, len, PBUF_RAM);
0132
0133 if (!p) {
0134 DLOG ("pbuf_alloc");
0135 return -1;
0136 }
0137
0138 if (pbuf_take (p, buf, len) != ERR_OK) {
0139 pbuf_free (p);
0140 DLOG ("pbuf_take");
0141 return -1;
0142 }
0143
0144 if (udp_sendto (pcb, p, &server_ip, server_port) != ERR_OK) {
0145 pbuf_free (p);
0146 DLOG ("udp_sendto");
0147 return -1;
0148 }
0149
0150 pbuf_free (p);
0151
0152 return len;
0153 }
0154
0155 static blocklist_t *
0156 alloc_node (void)
0157 {
0158 uint32 frame = alloc_phys_frame ();
0159 if (frame == -1) return NULL;
0160 return map_virtual_page (frame | 3);
0161 }
0162
0163 static void
0164 free_node (blocklist_t *bl)
0165 {
0166 uint32 frame = (uint32) get_phys_addr (bl);
0167 unmap_virtual_page (bl);
0168 free_phys_frame (frame);
0169 }
0170
0171 #define NODE_CAPACITY (BLOCKS_PER_NODE * TFTP_BLOCK_SIZE)
0172 static void
0173 cache (uint8 *buf, uint32 len)
0174 {
0175 while (len > 0) {
0176 if (curend && curend->len < NODE_CAPACITY) {
0177
0178 uint32 rem = NODE_CAPACITY - curend->len;
0179 uint32 amount = len < rem ? len : rem;
0180
0181 memcpy (&curend->blocks[curend->len], buf, amount);
0182 curend->len += amount;
0183 len -= amount;
0184 buf += amount;
0185 } else {
0186
0187 blocklist_t *n = alloc_node ();
0188 memset (n, 0, sizeof (blocklist_t));
0189 n->next = NULL;
0190 n->len = len < NODE_CAPACITY ? len : NODE_CAPACITY;
0191 memcpy (n->blocks, buf, n->len);
0192 if (curend) {
0193
0194 curend->next = n;
0195 curend = curend->next;
0196 } else
0197
0198 curbuf = curend = n;
0199 len -= n->len;
0200 buf += n->len;
0201 }
0202 }
0203 }
0204
0205 static void
0206 free_cache (void)
0207 {
0208 blocklist_t *bl;
0209 if (curbuf) {
0210 for (bl = curbuf; curbuf;) {
0211 bl = bl->next;
0212 free_node (curbuf);
0213 curbuf = bl;
0214 }
0215 }
0216 curend = curbuf = NULL;
0217 }
0218
0219 int
0220 eztftp_dir (char *pathname)
0221 {
0222 struct pbuf *p, *q;
0223 uint8 buf[TFTP_BLOCK_SIZE+4], *ins;
0224 uint32 len, rem, filesize=0;
0225
0226 circular_init (&incoming, incoming_buf,
0227 TFTP_RING_LEN, sizeof (struct pbuf *));
0228
0229 DLOG ("dir (%s)", pathname);
0230 if (pathname[0] == '/')
0231
0232 pathname++;
0233
0234 if (curbuf) free_cache ();
0235
0236
0237 len = format_rrq (buf, TFTP_BLOCK_SIZE+4, pathname);
0238 server_port = TFTP_PORT;
0239 if (send (buf, len) < 0) {
0240 DLOG ("failed to send request: %d %s", *((u16 *) buf), buf+2);
0241 return -1;
0242 }
0243
0244
0245 rem = TFTP_BLOCK_SIZE+4; len=0; ins=buf;
0246 for (;;) {
0247
0248 circular_remove (&incoming, &p);
0249 if (!p) continue;
0250
0251 while (rem > 0) {
0252
0253 memcpy (ins, p->payload, p->len);
0254
0255
0256 rem -= p->len;
0257 ins += p->len;
0258 len += p->len;
0259
0260
0261 q = p->next;
0262 if (q) pbuf_ref (q);
0263 pbuf_free (p);
0264 p = q;
0265
0266
0267 if (!p) break;
0268 }
0269
0270
0271 if (buf[1] == TFTP_OP_DATA) {
0272 DLOG ("received DATA packet num=0x%.04X len=%d bytes",
0273 (buf[2] << 8) | buf[3], len-4);
0274
0275 buf[1] = TFTP_OP_ACK;
0276 send (buf, 4);
0277
0278 cache (buf+4, len-4);
0279 } else if (buf[1] == TFTP_OP_ERR) {
0280
0281 DLOG ("error code=%d str=%s", (buf[2] << 8) | buf[3], &buf[4]);
0282 return -1;
0283 } else {
0284
0285 DLOG ("received unexpected packet opcode=%d", buf[1]);
0286 }
0287
0288 filesize += len-4;
0289
0290 if (len - 4 < TFTP_BLOCK_SIZE)
0291
0292 break;
0293
0294
0295 rem = TFTP_BLOCK_SIZE+4; len=0; ins=buf;
0296 }
0297
0298 DLOG ("opened file size=%d bytes", filesize);
0299 return filesize;
0300 }
0301
0302 int
0303 eztftp_read (char *buf, int len)
0304 {
0305 char *ptr = buf;
0306 int actual = 0;
0307 DLOG ("read (%p, %d)", buf, len);
0308 while (len > 0 && curbuf) {
0309 int amount = len < curbuf->len ? len : curbuf->len;
0310
0311
0312 memcpy (ptr, &curbuf->blocks[curbuf->start], amount);
0313 ptr += amount;
0314 actual += amount;
0315 curbuf->start += amount;
0316 len -= amount;
0317 curbuf->len -= amount;
0318
0319
0320 if (curbuf->len <= 0) {
0321 blocklist_t *n = curbuf->next;
0322 free_node (curbuf);
0323 curbuf = n;
0324 if (curbuf == NULL)
0325 curend = NULL;
0326 }
0327 }
0328
0329 return actual;
0330 }
0331
0332 static void
0333 recv_callback (void *arg, struct udp_pcb *pcb, struct pbuf *p,
0334 struct ip_addr *addr, uint16 port)
0335 {
0336
0337 DLOG ("recv_callback: addr=%p port=0x%.04X p->tot_len=%d bytes",
0338 addr->addr, port, p->tot_len);
0339 server_port = port;
0340 circular_insert_nowait (&incoming, &p);
0341 }
0342
0343 bool
0344 eztftp_mount (char *ifname)
0345 {
0346 DLOG ("mount %s", ifname);
0347 circular_init (&incoming, incoming_buf,
0348 TFTP_RING_LEN, sizeof (struct pbuf *));
0349 server_if = netif_find (ifname);
0350 if (server_if == NULL) return FALSE;
0351 server_ip.addr = 0;
0352 pcb = udp_new ();
0353 if (!pcb) return FALSE;
0354 if (udp_bind (pcb, IP_ADDR_ANY, 0) != ERR_OK)
0355 return FALSE;
0356 udp_recv (pcb, recv_callback, NULL);
0357 return TRUE;
0358 }
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369