+ if (argv[0]) {
+ xchroot(argv[0]);
+ }
+
+ result = recv_from_to(STDIN_FILENO, block_buf, sizeof(block_buf),
+ 0 /* flags */,
+ &peer_lsa->u.sa, &our_lsa->u.sa, our_lsa->len);
+
+ error_msg = "malformed packet";
+ opcode = ntohs(*(uint16_t*)block_buf);
+ if (result < 4 || result >= sizeof(block_buf)
+ || block_buf[result-1] != '\0'
+ || (IF_FEATURE_TFTP_PUT(opcode != TFTP_RRQ) /* not download */
+ IF_GETPUT(&&)
+ IF_FEATURE_TFTP_GET(opcode != TFTP_WRQ) /* not upload */
+ )
+ ) {
+ goto err;
+ }
+ local_file = block_buf + 2;
+ if (local_file[0] == '.' || strstr(local_file, "/.")) {
+ error_msg = "dot in file name";
+ goto err;
+ }
+ mode = local_file + strlen(local_file) + 1;
+ /* RFC 1350 says mode string is case independent */
+ if (mode >= block_buf + result || strcasecmp(mode, "octet") != 0) {
+ goto err;
+ }
+# if ENABLE_FEATURE_TFTP_BLOCKSIZE
+ {
+ char *res;
+ char *opt_str = mode + sizeof("octet");
+ int opt_len = block_buf + result - opt_str;
+ if (opt_len > 0) {
+ res = tftp_get_option("blksize", opt_str, opt_len);
+ if (res) {
+ blksize = tftp_blksize_check(res, 65564);
+ if (blksize < 0) {
+ error_pkt_reason = ERR_BAD_OPT;
+ /* will just send error pkt */
+ goto do_proto;
+ }
+ }
+ if (opcode != TFTP_WRQ /* download? */
+ /* did client ask us about file size? */
+ && tftp_get_option("tsize", opt_str, opt_len)
+ ) {
+ want_transfer_size = 1;
+ }
+ }
+ }
+# endif
+
+ if (!ENABLE_FEATURE_TFTP_PUT || opcode == TFTP_WRQ) {
+ if (opt & TFTPD_OPT_r) {
+ /* This would mean "disk full" - not true */
+ /*error_pkt_reason = ERR_WRITE;*/
+ error_msg = bb_msg_write_error;
+ goto err;
+ }
+ IF_GETPUT(option_mask32 |= TFTP_OPT_GET;) /* will receive file's data */
+ } else {
+ IF_GETPUT(option_mask32 |= TFTP_OPT_PUT;) /* will send file's data */
+ }
+
+ /* NB: if error_pkt_str or error_pkt_reason is set up,
+ * tftp_protocol() just sends one error pkt and returns */
+
+ do_proto:
+ close(STDIN_FILENO); /* close old, possibly wildcard socket */
+ /* tftp_protocol() will create new one, bound to particular local IP */
+ result = tftp_protocol(
+ our_lsa, peer_lsa,
+ local_file IF_TFTP(, NULL /*remote_file*/)
+ IF_FEATURE_TFTP_BLOCKSIZE(, want_transfer_size)
+ IF_FEATURE_TFTP_BLOCKSIZE(, blksize)
+ );
+