static int tftp_ack(int *err) { struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data; // ACK last packet so server can shut down if (tftp_stream.packets_received > 0) { hdr->th_opcode = htons(ACK); hdr->th_block = htons((cyg_uint16)tftp_stream.last_good_block & 0xFFFF); if (__udp_sendto(tftp_stream.data, 4 /* FIXME */, &tftp_stream.from_addr, &tftp_stream.local_addr) < 0) { // Problem sending ACK *err = TFTP_NETERR; return -1; } } return 0; }
/* Send the query to the server and read the response back. Return -1 if it fails, otherwise put the response back in msg and return the length of the response. */ static int send_recv(char * msg, int len, int msglen) { struct dns_header *dns_hdr; int finished = false; int read = 0; dns_hdr = (struct dns_header *) msg; do { int len_togo = len; struct timeval timeout; struct sockaddr_in local_addr, from_addr; memset((char *)&local_addr, 0, sizeof(local_addr)); local_addr.sin_family = AF_INET; local_addr.sin_addr.s_addr = htonl(INADDR_ANY); local_addr.sin_port = htons(get_port++); if (__udp_sendto(msg, len_togo, &server, &local_addr) < 0) return -1; memset((char *)&from_addr, 0, sizeof(from_addr)); timeout.tv_sec = CYGNUM_REDBOOT_NETWORKING_DNS_TIMEOUT; timeout.tv_usec = 0; read = __udp_recvfrom(msg, len, &from_addr, &local_addr, &timeout); if (read < 0) return -1; /* Reply to an old query. Ignore it */ if (ntohs(dns_hdr->id) != (id-1)) { continue; } finished = true; } while (!finished); return read; }
int tftp_stream_open(connection_info_t *info, int *err) { struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data; char *cp, *fp; char test_buf; if (!have_net || tftp_stream.open) { *err = TFTP_INVALID; // Already open return -1; } // Create initial request hdr->th_opcode = htons(RRQ); // Read file cp = (char *)&hdr->th_stuff; fp = info->filename; while (*fp) *cp++ = *fp++; *cp++ = '\0'; // Since this is used for downloading data, OCTET (binary) is the // only mode that makes sense. fp = "OCTET"; while (*fp) *cp++ = *fp++; *cp++ = '\0'; memset((char *)&tftp_stream.local_addr, 0, sizeof(tftp_stream.local_addr)); tftp_stream.local_addr.sin_family = AF_INET; tftp_stream.local_addr.sin_addr.s_addr = htonl(INADDR_ANY); tftp_stream.local_addr.sin_port = htons(get_port++); if (info->server->sin_port == 0) { info->server->sin_port = htons(TFTP_PORT); } else { info->server->sin_port = htons(info->server->sin_port); } // Send request - note: RFC 1350 (TFTP rev 2) indicates that this should be // only as long as required to hold the request, with the nul terminator. // Some servers silently go to lunch if the request is not the correct size. if (__udp_sendto(tftp_stream.data, cp-(char *)hdr, info->server, &tftp_stream.local_addr) < 0) { // Problem sending request *err = TFTP_NETERR; return -1; } tftp_stream.open = true; tftp_stream.avail = 0; tftp_stream.actual_len = -1; tftp_stream.last_good_block = 0; tftp_stream.total_timeouts = 0; tftp_stream.from_addr.sin_port = 0; tftp_stream.packets_received = 0; // Try and read the first byte [block] since no errors are // reported until then. if (tftp_stream_read(&test_buf, 1, err) == 1) { // Back up [rewind] over this datum tftp_stream.bufp--; tftp_stream.avail++; return 0; // Open and first read successful } else { tftp_stream.open = false; return -1; // Couldn't read } }