slirp: support dynamic block size for TFTP transfers

The blocksize option is defined in RFC 1783 and RFC 2348.
We now support block sizes between 1 and 1428 bytes, instead of 512 only.

Signed-off-by: Hervé Poussineau <hpoussin@reactos.org>
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
This commit is contained in:
Hervé Poussineau 2016-11-21 20:45:49 +01:00 committed by Samuel Thibault
parent 893dcdbfa9
commit 9443598d7e
2 changed files with 19 additions and 15 deletions

View File

@ -72,6 +72,7 @@ static int tftp_session_allocate(Slirp *slirp, struct sockaddr_storage *srcsas,
memset(spt, 0, sizeof(*spt)); memset(spt, 0, sizeof(*spt));
spt->client_addr = *srcsas; spt->client_addr = *srcsas;
spt->fd = -1; spt->fd = -1;
spt->block_size = 512;
spt->client_port = tp->udp.uh_sport; spt->client_port = tp->udp.uh_sport;
spt->slirp = slirp; spt->slirp = slirp;
@ -115,7 +116,7 @@ static int tftp_read_data(struct tftp_session *spt, uint32_t block_nr,
} }
if (len) { if (len) {
lseek(spt->fd, block_nr * 512, SEEK_SET); lseek(spt->fd, block_nr * spt->block_size, SEEK_SET);
bytes_read = read(spt->fd, buf, len); bytes_read = read(spt->fd, buf, len);
} }
@ -189,7 +190,8 @@ static int tftp_send_oack(struct tftp_session *spt,
values[i]) + 1; values[i]) + 1;
} }
m->m_len = sizeof(struct tftp_t) - 514 + n - sizeof(struct udphdr); m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX + 2) + n
- sizeof(struct udphdr);
tftp_udp_output(spt, m, recv_tp); tftp_udp_output(spt, m, recv_tp);
return 0; return 0;
@ -214,7 +216,7 @@ static void tftp_send_error(struct tftp_session *spt,
tp->x.tp_error.tp_error_code = htons(errorcode); tp->x.tp_error.tp_error_code = htons(errorcode);
pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg), msg); pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg), msg);
m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX + 2) + 3 + strlen(msg)
- sizeof(struct udphdr); - sizeof(struct udphdr);
tftp_udp_output(spt, m, recv_tp); tftp_udp_output(spt, m, recv_tp);
@ -240,7 +242,8 @@ static void tftp_send_next_block(struct tftp_session *spt,
tp->tp_op = htons(TFTP_DATA); tp->tp_op = htons(TFTP_DATA);
tp->x.tp_data.tp_block_nr = htons((spt->block_nr + 1) & 0xffff); tp->x.tp_data.tp_block_nr = htons((spt->block_nr + 1) & 0xffff);
nobytes = tftp_read_data(spt, spt->block_nr, tp->x.tp_data.tp_buf, 512); nobytes = tftp_read_data(spt, spt->block_nr, tp->x.tp_data.tp_buf,
spt->block_size);
if (nobytes < 0) { if (nobytes < 0) {
m_free(m); m_free(m);
@ -252,10 +255,11 @@ static void tftp_send_next_block(struct tftp_session *spt,
return; return;
} }
m->m_len = sizeof(struct tftp_t) - (512 - nobytes) - sizeof(struct udphdr); m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX - nobytes)
- sizeof(struct udphdr);
tftp_udp_output(spt, m, recv_tp); tftp_udp_output(spt, m, recv_tp);
if (nobytes == 512) { if (nobytes == spt->block_size) {
tftp_session_update(spt); tftp_session_update(spt);
} }
else { else {
@ -385,13 +389,11 @@ static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas,
} else if (strcasecmp(key, "blksize") == 0) { } else if (strcasecmp(key, "blksize") == 0) {
int blksize = atoi(value); int blksize = atoi(value);
/* If blksize option is bigger than what we will /* Accept blksize up to our maximum size */
* emit, accept the option with our packet size. if (blksize > 0) {
* Otherwise, simply do as we didn't see the option. spt->block_size = MIN(blksize, TFTP_BLOCKSIZE_MAX);
*/
if (blksize >= 512) {
option_name[nb_options] = "blksize"; option_name[nb_options] = "blksize";
option_value[nb_options] = 512; option_value[nb_options] = spt->block_size;
nb_options++; nb_options++;
} }
} }

View File

@ -15,6 +15,7 @@
#define TFTP_OACK 6 #define TFTP_OACK 6
#define TFTP_FILENAME_MAX 512 #define TFTP_FILENAME_MAX 512
#define TFTP_BLOCKSIZE_MAX 1428
struct tftp_t { struct tftp_t {
struct udphdr udp; struct udphdr udp;
@ -22,13 +23,13 @@ struct tftp_t {
union { union {
struct { struct {
uint16_t tp_block_nr; uint16_t tp_block_nr;
uint8_t tp_buf[512]; uint8_t tp_buf[TFTP_BLOCKSIZE_MAX];
} tp_data; } tp_data;
struct { struct {
uint16_t tp_error_code; uint16_t tp_error_code;
uint8_t tp_msg[512]; uint8_t tp_msg[TFTP_BLOCKSIZE_MAX];
} tp_error; } tp_error;
char tp_buf[512 + 2]; char tp_buf[TFTP_BLOCKSIZE_MAX + 2];
} x; } x;
} __attribute__((packed)); } __attribute__((packed));
@ -36,6 +37,7 @@ struct tftp_session {
Slirp *slirp; Slirp *slirp;
char *filename; char *filename;
int fd; int fd;
uint16_t block_size;
struct sockaddr_storage client_addr; struct sockaddr_storage client_addr;
uint16_t client_port; uint16_t client_port;