--- busybox-1.4.1/include/libbb.h Wed Jan 24 22:34:48 2007 +++ busybox-1.4.1-tftp/include/libbb.h Sat Mar 3 00:02:34 2007 @@ -290,7 +290,7 @@ /* "new" (ipv4+ipv6) API */ typedef struct len_and_sockaddr { - int len; + socklen_t len; union { struct sockaddr sa; struct sockaddr_in sin; --- busybox-1.4.1/networking/tftp.c Wed Jan 24 22:34:34 2007 +++ busybox-1.4.1-tftp/networking/tftp.c Sat Mar 3 00:02:56 2007 @@ -132,7 +132,7 @@ #if ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT const int cmd, #endif - const len_and_sockaddr *peer_lsa, + len_and_sockaddr *peer_lsa, const char *remotefile, const int localfd, unsigned port, int tftp_bufsize) { @@ -149,6 +149,9 @@ USE_FEATURE_TFTP_BLOCKSIZE(int want_option_ack = 0;) + unsigned org_port; + len_and_sockaddr *const from = alloca(offsetof(len_and_sockaddr, sa) + peer_lsa->len); + /* Can't use RESERVE_CONFIG_BUFFER here since the allocation * size varies meaning BUFFERS_GO_ON_STACK would fail */ /* We must keep the transmit and receive buffers seperate */ @@ -156,7 +159,7 @@ char *xbuf = xmalloc(tftp_bufsize += 4); char *rbuf = xmalloc(tftp_bufsize); - port = htons(port); + port = org_port = htons(port); socketfd = xsocket(peer_lsa->sa.sa_family, SOCK_DGRAM, 0); @@ -167,10 +170,10 @@ } while (1) { - cp = xbuf; /* first create the opcode part */ + /* (this 16bit store is aligned) */ *((uint16_t*)cp) = htons(opcode); cp += 2; @@ -222,6 +225,7 @@ /* add ack and data */ if (CMD_GET(cmd) ? (opcode == TFTP_ACK) : (opcode == TFTP_DATA)) { + /* TODO: unaligned access! */ *((uint16_t*)cp) = htons(block_nr); cp += 2; block_nr++; @@ -273,28 +277,26 @@ FD_SET(socketfd, &rfds); switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) { - struct sockaddr *from; - socklen_t fromlen; - + unsigned from_port; case 1: - fromlen = peer_lsa->len; - from = alloca(fromlen); - memset(from, 0, fromlen); - + from->len = peer_lsa->len; + memset(&from->sa, 0, peer_lsa->len); len = recvfrom(socketfd, rbuf, tftp_bufsize, 0, - from, &fromlen); + &from->sa, &from->len); if (len < 0) { bb_perror_msg("recvfrom"); break; } -#if ENABLE_FEATURE_IPV6 - if (from->sa_family == AF_INET6) - if (((struct sockaddr_in6*)from)->sin6_port != port) - goto recv_again; -#endif - if (from->sa_family == AF_INET) - if (((struct sockaddr_in*)from)->sin_port != port) - goto recv_again; + from_port = get_nport(from); + if (port == org_port) { + /* Our first query went to port 69 + * but reply will come from different one. + * Remember and use this new port */ + port = from_port; + set_nport(peer_lsa, from_port); + } + if (port != from_port) + goto recv_again; timeout = 0; break; case 0: @@ -317,6 +319,7 @@ } /* process received packet */ + /* (both accesses seems to be aligned) */ opcode = ntohs( ((uint16_t*)rbuf)[0] ); tmp = ntohs( ((uint16_t*)rbuf)[1] );