aboutsummaryrefslogtreecommitdiff
path: root/networking/tftp.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-02-07 23:20:32 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-02-07 23:20:32 +0000
commit0850cdabded5ee04e243e45d419d7707da78bb51 (patch)
treef3edd429d95cfa19f9ae603053751247a750e534 /networking/tftp.c
parent8c6c6e955b4a73b8a2cac8c0d277bc109b329908 (diff)
downloadbusybox-w32-0850cdabded5ee04e243e45d419d7707da78bb51.tar.gz
busybox-w32-0850cdabded5ee04e243e45d419d7707da78bb51.tar.bz2
busybox-w32-0850cdabded5ee04e243e45d419d7707da78bb51.zip
tftp: fix IPv6 fallout
Diffstat (limited to 'networking/tftp.c')
-rw-r--r--networking/tftp.c41
1 files changed, 22 insertions, 19 deletions
diff --git a/networking/tftp.c b/networking/tftp.c
index 9083257ab..ada38bc44 100644
--- a/networking/tftp.c
+++ b/networking/tftp.c
@@ -132,7 +132,7 @@ static int tftp(
132#if ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT 132#if ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT
133 const int cmd, 133 const int cmd,
134#endif 134#endif
135 const len_and_sockaddr *peer_lsa, 135 len_and_sockaddr *peer_lsa,
136 const char *remotefile, const int localfd, 136 const char *remotefile, const int localfd,
137 unsigned port, int tftp_bufsize) 137 unsigned port, int tftp_bufsize)
138{ 138{
@@ -149,6 +149,9 @@ static int tftp(
149 149
150 USE_FEATURE_TFTP_BLOCKSIZE(int want_option_ack = 0;) 150 USE_FEATURE_TFTP_BLOCKSIZE(int want_option_ack = 0;)
151 151
152 unsigned org_port;
153 len_and_sockaddr *const from = alloca(offsetof(len_and_sockaddr, sa) + peer_lsa->len);
154
152 /* Can't use RESERVE_CONFIG_BUFFER here since the allocation 155 /* Can't use RESERVE_CONFIG_BUFFER here since the allocation
153 * size varies meaning BUFFERS_GO_ON_STACK would fail */ 156 * size varies meaning BUFFERS_GO_ON_STACK would fail */
154 /* We must keep the transmit and receive buffers seperate */ 157 /* We must keep the transmit and receive buffers seperate */
@@ -156,7 +159,7 @@ static int tftp(
156 char *xbuf = xmalloc(tftp_bufsize += 4); 159 char *xbuf = xmalloc(tftp_bufsize += 4);
157 char *rbuf = xmalloc(tftp_bufsize); 160 char *rbuf = xmalloc(tftp_bufsize);
158 161
159 port = htons(port); 162 port = org_port = htons(port);
160 163
161 socketfd = xsocket(peer_lsa->sa.sa_family, SOCK_DGRAM, 0); 164 socketfd = xsocket(peer_lsa->sa.sa_family, SOCK_DGRAM, 0);
162 165
@@ -167,10 +170,10 @@ static int tftp(
167 } 170 }
168 171
169 while (1) { 172 while (1) {
170
171 cp = xbuf; 173 cp = xbuf;
172 174
173 /* first create the opcode part */ 175 /* first create the opcode part */
176 /* (this 16bit store is aligned) */
174 *((uint16_t*)cp) = htons(opcode); 177 *((uint16_t*)cp) = htons(opcode);
175 cp += 2; 178 cp += 2;
176 179
@@ -222,6 +225,7 @@ static int tftp(
222 /* add ack and data */ 225 /* add ack and data */
223 226
224 if (CMD_GET(cmd) ? (opcode == TFTP_ACK) : (opcode == TFTP_DATA)) { 227 if (CMD_GET(cmd) ? (opcode == TFTP_ACK) : (opcode == TFTP_DATA)) {
228 /* TODO: unaligned access! */
225 *((uint16_t*)cp) = htons(block_nr); 229 *((uint16_t*)cp) = htons(block_nr);
226 cp += 2; 230 cp += 2;
227 block_nr++; 231 block_nr++;
@@ -273,28 +277,26 @@ static int tftp(
273 FD_SET(socketfd, &rfds); 277 FD_SET(socketfd, &rfds);
274 278
275 switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) { 279 switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) {
276 struct sockaddr *from; 280 unsigned from_port;
277 socklen_t fromlen;
278
279 case 1: 281 case 1:
280 fromlen = peer_lsa->len; 282 from->len = peer_lsa->len;
281 from = alloca(fromlen); 283 memset(from, 0, peer_lsa->len);
282 memset(from, 0, fromlen);
283
284 len = recvfrom(socketfd, rbuf, tftp_bufsize, 0, 284 len = recvfrom(socketfd, rbuf, tftp_bufsize, 0,
285 from, &fromlen); 285 &from->sa, &from->len);
286 if (len < 0) { 286 if (len < 0) {
287 bb_perror_msg("recvfrom"); 287 bb_perror_msg("recvfrom");
288 break; 288 break;
289 } 289 }
290#if ENABLE_FEATURE_IPV6 290 from_port = get_nport(from);
291 if (from->sa_family == AF_INET6) 291 if (port == org_port) {
292 if (((struct sockaddr_in6*)from)->sin6_port != port) 292 /* Our first query went to port 69
293 goto recv_again; 293 * but reply will come from different one.
294#endif 294 * Remember and use this new port */
295 if (from->sa_family == AF_INET) 295 port = from_port;
296 if (((struct sockaddr_in*)from)->sin_port != port) 296 set_nport(peer_lsa, from_port);
297 goto recv_again; 297 }
298 if (port != from_port)
299 goto recv_again;
298 timeout = 0; 300 timeout = 0;
299 break; 301 break;
300 case 0: 302 case 0:
@@ -317,6 +319,7 @@ static int tftp(
317 } 319 }
318 320
319 /* process received packet */ 321 /* process received packet */
322 /* (both accesses seems to be aligned) */
320 323
321 opcode = ntohs( ((uint16_t*)rbuf)[0] ); 324 opcode = ntohs( ((uint16_t*)rbuf)[0] );
322 tmp = ntohs( ((uint16_t*)rbuf)[1] ); 325 tmp = ntohs( ((uint16_t*)rbuf)[1] );