static int tftp_read(struct device_d *dev, FILE *f, void *buf, size_t insize) { struct file_priv *priv = f->inode; size_t outsize = 0, now; int ret; debug("%s %zu\n", __func__, insize); while (insize) { now = kfifo_get(priv->fifo, buf, insize); if (priv->state == STATE_DONE) return outsize + now; if (now) { outsize += now; buf += now; insize -= now; } if (TFTP_FIFO_SIZE - kfifo_len(priv->fifo) >= priv->blocksize) tftp_send(priv); ret = tftp_poll(priv); if (ret == TFTP_ERR_RESEND) tftp_send(priv); if (ret < 0) return ret; } return outsize; }
void tftpd_general(void *p_info, int socket_ID) { connect_info_S *p_con_info=(connect_info_S *)p_info; FILE *f; int result=255; if (p_con_info->job==RRQ) { f=fopen(p_con_info->p_name,"rb"); if(f == NULL) { nak(socket_ID, &p_con_info->adresse, errno,strerror(errno)); tftp_free(p_con_info->p_name); tftp_free(p_con_info); close(socket_ID); return ; } result=tftp_send(&p_con_info->adresse,p_con_info->p_name,"octet",0,TFTPsread,f); fclose(f); } else if (p_con_info->job==WRQ) { result=tftp_receive(&p_con_info->adresse,p_con_info->p_name,"octet",0,TFTPswrite,f); } else { DEBUG_MSG("TFTP op code is not correct \n"); } if (result!=0) DEBUG_MSG("TFTP error\n"); tftp_free(p_con_info->p_name); tftp_free(p_con_info); return ; }
static void tftp_xmitfile(int peer, const char *mode) { uint16_t block; time_t now; struct tftp_stats ts; now = time(NULL); if (debug&DEBUG_SIMPLE) tftp_log(LOG_DEBUG, "Transmitting file"); read_init(0, file, mode); block = 1; tftp_send(peer, &block, &ts); read_close(); if (debug&DEBUG_SIMPLE) tftp_log(LOG_INFO, "Sent %jd bytes in %jd seconds", (intmax_t)ts.amount, (intmax_t)time(NULL) - now); }
static struct file_priv *tftp_do_open(struct device_d *dev, int accmode, const char *filename) { struct file_priv *priv; struct tftp_priv *tpriv = dev->priv; int ret; priv = xzalloc(sizeof(*priv)); filename++; switch (accmode & O_ACCMODE) { case O_RDONLY: priv->push = 0; priv->state = STATE_RRQ; break; case O_WRONLY: priv->push = 1; priv->state = STATE_WRQ; break; case O_RDWR: ret = -ENOSYS; goto out; } priv->block = 1; priv->err = -EINVAL; priv->filename = filename; priv->blocksize = TFTP_BLOCK_SIZE; priv->block_requested = -1; priv->fifo = kfifo_alloc(TFTP_FIFO_SIZE); if (!priv->fifo) { ret = -ENOMEM; goto out; } priv->tftp_con = net_udp_new(tpriv->server, TFTP_PORT, tftp_handler, priv); if (IS_ERR(priv->tftp_con)) { ret = PTR_ERR(priv->tftp_con); goto out1; } ret = tftp_send(priv); if (ret) goto out2; tftp_timer_reset(priv); while (priv->state != STATE_RDATA && priv->state != STATE_DONE && priv->state != STATE_WDATA) { ret = tftp_poll(priv); if (ret == TFTP_ERR_RESEND) tftp_send(priv); if (ret < 0) goto out2; } if (priv->state == STATE_DONE && priv->err) { ret = priv->err; goto out2; } priv->buf = xmalloc(priv->blocksize); return priv; out2: net_unregister(priv->tftp_con); out1: kfifo_free(priv->fifo); out: free(priv); return ERR_PTR(ret); }
static void tftp_handler(void *ctx, char *packet, unsigned len) { struct file_priv *priv = ctx; uint16_t proto; uint16_t *s; char *pkt = net_eth_to_udp_payload(packet); struct udphdr *udp = net_eth_to_udphdr(packet); len = net_eth_to_udplen(packet); if (len < 2) return; len -= 2; s = (uint16_t *)pkt; proto = *s++; pkt = (unsigned char *)s; debug("%s: proto 0x%04x\n", __func__, proto); switch (ntohs(proto)) { case TFTP_RRQ: case TFTP_WRQ: default: break; case TFTP_ACK: if (!priv->push) break; priv->block = ntohs(*(uint16_t *)pkt); if (priv->block != priv->last_block) { debug("ack %d != %d\n", priv->block, priv->last_block); break; } priv->block++; tftp_timer_reset(priv); if (priv->state == STATE_LAST) { priv->state = STATE_DONE; break; } priv->tftp_con->udp->uh_dport = udp->uh_sport; priv->state = STATE_WDATA; break; case TFTP_OACK: tftp_parse_oack(priv, pkt, len); priv->server_port = ntohs(udp->uh_sport); priv->tftp_con->udp->uh_dport = udp->uh_sport; if (priv->push) { /* send first block */ priv->state = STATE_WDATA; priv->block = 1; } else { /* send ACK */ priv->state = STATE_OACK; priv->block = 0; tftp_send(priv); } break; case TFTP_DATA: if (len < 2) return; len -= 2; priv->block = ntohs(*(uint16_t *)pkt); if (priv->state == STATE_RRQ || priv->state == STATE_OACK) { /* first block received */ priv->state = STATE_RDATA; priv->tftp_con->udp->uh_dport = udp->uh_sport; priv->server_port = ntohs(udp->uh_sport); priv->last_block = 0; if (priv->block != 1) { /* Assertion */ printf("error: First block is not block 1 (%d)\n", priv->block); priv->err = -EINVAL; priv->state = STATE_DONE; break; } } if (priv->block == priv->last_block) /* Same block again; ignore it. */ break; priv->last_block = priv->block; tftp_timer_reset(priv); kfifo_put(priv->fifo, pkt + 2, len); if (len < priv->blocksize) { tftp_send(priv); priv->err = 0; priv->state = STATE_DONE; } break; case TFTP_ERROR: debug("\nTFTP error: '%s' (%d)\n", pkt + 2, ntohs(*(uint16_t *)pkt)); switch (ntohs(*(uint16_t *)pkt)) { case 1: priv->err = -ENOENT; break; case 2: priv->err = -EACCES; break; default: priv->err = -EINVAL; break; } priv->state = STATE_DONE; break; } }
/* * Send the requested file. */ void xmitfile(int peer, char *port, int fd, char *name, char *mode) { struct tftphdr *rp; int n, i; uint16_t block; struct sockaddr_storage serv; /* valid server port number */ char recvbuffer[MAXPKTSIZE]; struct tftp_stats tftp_stats; stats_init(&tftp_stats); memset(&serv, 0, sizeof(serv)); rp = (struct tftphdr *)recvbuffer; if (port == NULL) { struct servent *se; se = getservbyname("tftp", "udp"); ((struct sockaddr_in *)&peer_sock)->sin_port = se->s_port; } else ((struct sockaddr_in *)&peer_sock)->sin_port = htons(atoi(port)); for (i = 0; i < 12; i++) { struct sockaddr_storage from; /* Tell the other side what we want to do */ if (debug&DEBUG_SIMPLE) printf("Sending %s\n", name); n = send_wrq(peer, name, mode); if (n > 0) { printf("Cannot send WRQ packet\n"); return; } /* * The first packet we receive has the new destination port * we have to send the next packets to. */ n = receive_packet(peer, recvbuffer, MAXPKTSIZE, &from, timeoutpacket); /* We got some data! */ if (n >= 0) { ((struct sockaddr_in *)&peer_sock)->sin_port = ((struct sockaddr_in *)&from)->sin_port; break; } /* This should be retried */ if (n == RP_TIMEOUT) { printf("Try %d, didn't receive answer from remote.\n", i + 1); continue; } /* Everything else is fatal */ break; } if (i == 12) { printf("Transfer timed out.\n"); return; } if (rp->th_opcode == ERROR) { printf("Got ERROR, aborted\n"); return; } /* * If the first packet is an OACK instead of an ACK packet, * handle it different. */ if (rp->th_opcode == OACK) { if (!options_rfc_enabled) { printf("Got OACK while options are not enabled!\n"); send_error(peer, EBADOP); return; } parse_options(peer, rp->th_stuff, n + 2); } if (read_init(fd, NULL, mode) < 0) { warn("read_init()"); return; } block = 1; tftp_send(peer, &block, &tftp_stats); read_close(); if (tftp_stats.amount > 0) printstats("Sent", verbose, &tftp_stats); txrx_error = 1; }