X-Git-Url: https://git.kernelconcepts.de/?p=karo-tx-redboot.git;a=blobdiff_plain;f=packages%2Fnet%2Fcommon%2Fv2_0%2Fsrc%2Ftftp_client.c;h=a719099305eb51c0934e1c5db121f0c3ed6b8082;hp=c11eb11ea20ca5bc92ebab0ffa41196f70fd4855;hb=7a4ea0a4d67744fd3f6b5f207d857005fc707b46;hpb=f0c1bd5d9f8457be4a43912a28ca2df207a7f5a4 diff --git a/packages/net/common/v2_0/src/tftp_client.c b/packages/net/common/v2_0/src/tftp_client.c index c11eb11e..a7190993 100644 --- a/packages/net/common/v2_0/src/tftp_client.c +++ b/packages/net/common/v2_0/src/tftp_client.c @@ -57,6 +57,8 @@ #include #include #include +#include +#include #define min(x,y) (xai_family, addrinfo->ai_socktype, - addrinfo->ai_protocol); + addrinfo->ai_protocol); if (s >= 0) { - memcpy(&local_addr,addrinfo->ai_addr,addrinfo->ai_addrlen); - switch(addrinfo->ai_addr->sa_family) { - case AF_INET: { - struct sockaddr_in * saddr = - (struct sockaddr_in *) addrinfo->ai_addr; - struct sockaddr_in * laddr = - (struct sockaddr_in *) &local_addr; - if (port) { - saddr->sin_port = htons(port); - } - laddr->sin_port = htons(get_port++); - laddr->sin_addr.s_addr = INADDR_ANY; - break; - } + memcpy(&local_addr,addrinfo->ai_addr,addrinfo->ai_addrlen); + switch(addrinfo->ai_addr->sa_family) { + case AF_INET: { + struct sockaddr_in * saddr = + (struct sockaddr_in *) addrinfo->ai_addr; + struct sockaddr_in * laddr = + (struct sockaddr_in *) &local_addr; + if (port) { + saddr->sin_port = htons(port); + } + laddr->sin_port = htons(get_port++); + laddr->sin_addr.s_addr = INADDR_ANY; + break; + } #ifdef CYGPKG_NET_INET6 - case AF_INET6: { - struct sockaddr_in6 * saddr = - (struct sockaddr_in6 *) addrinfo->ai_addr; - struct sockaddr_in6 * laddr = - (struct sockaddr_in6 *) &local_addr; - if (port) { - saddr->sin6_port = htons(port); - } - laddr->sin6_port = htons(get_port++); - laddr->sin6_addr = in6addr_any; - break; - } + case AF_INET6: { + struct sockaddr_in6 * saddr = + (struct sockaddr_in6 *) addrinfo->ai_addr; + struct sockaddr_in6 * laddr = + (struct sockaddr_in6 *) &local_addr; + if (port) { + saddr->sin6_port = htons(port); + } + laddr->sin6_port = htons(get_port++); + laddr->sin6_addr = in6addr_any; + break; + } #endif - default: - *err = TFTP_NETERR; - goto out; - } + default: + *err = TFTP_NETERR; + goto out; + } - if (bind(s,&local_addr,addrinfo->ai_addrlen) < 0) { + if (bind(s,&local_addr,addrinfo->ai_addrlen) < 0) { *err = TFTP_NETERR; goto out; } - - // Send request - if (sendto(s, data, (int)(cp-data), 0, - addrinfo->ai_addr, - addrinfo->ai_addrlen) < 0) { - // Problem sending request - *err = TFTP_NETERR; - goto nextaddr; - } + + // Send request + if (sendto(s, data, (int)(cp-data), 0, + addrinfo->ai_addr, + addrinfo->ai_addrlen) < 0) { + // Problem sending request + *err = TFTP_NETERR; + goto nextaddr; + } - // Read data - fp = buf; - while (true) { - timeout.tv_sec = TFTP_TIMEOUT_PERIOD; - timeout.tv_usec = 0; - FD_ZERO(&fds); - FD_SET(s, &fds); - if (select(s+1, &fds, 0, 0, &timeout) <= 0) { + // Read data + bp = buf; + while (true) { + timeout.tv_sec = TFTP_TIMEOUT_PERIOD; + timeout.tv_usec = 0; + FD_ZERO(&fds); + FD_SET(s, &fds); + if (select(s+1, &fds, 0, 0, &timeout) <= 0) { total_timeouts++; if ((last_good_block == 0) && (total_timeouts > TFTP_RETRIES_MAX)) { - // Timeout - no data received. Probably no server. - *err = TFTP_TIMEOUT; - goto nextaddr; + // Timeout - no data received. Probably no server. + *err = TFTP_TIMEOUT; + goto nextaddr; } - if (total_timeouts > TFTP_TIMEOUT_MAX) { + if (total_timeouts > TFTP_TIMEOUT_MAX) { // Timeout - have received data. Network problem? *err = TFTP_TIMEOUT; goto out; - } + } if (last_good_block == 0 ) { // Send request @@ -212,72 +230,92 @@ int tftp_client_get(char *filename, goto out; } } - } else { - recv_len = sizeof(data); - from_len = sizeof(from_addr); - if ((data_len = recvfrom(s, &data, recv_len, 0, - &from_addr, &from_len)) < 0) { - // What happened? - *err = TFTP_NETERR; - goto out; - } - if (ntohs(hdr->th_opcode) == DATA) { - actual_len = 0; - if (ntohs(hdr->th_block) == (last_good_block+1)) { - // Consume this data - cp = hdr->th_data; - data_len -= 4; /* Sizeof TFTP header */ - actual_len = data_len; - result += actual_len; - while (data_len-- > 0) { - if (len-- > 0) { - *fp++ = *cp++; - } else { - // Buffer overflow - *err = TFTP_TOOLARGE; - goto out; - } - } - last_good_block++; - } else { - // To prevent an out-of-sequence packet from - // terminating transmission prematurely, set - // actual_len to a full size packet. - actual_len = SEGSIZE; - } - // Send out the ACK - hdr->th_opcode = htons(ACK); - hdr->th_block = htons(last_good_block); - if (sendto(s, data, 4 /* FIXME */, 0, - &from_addr, from_len) < 0) { - // Problem sending request - *err = TFTP_NETERR; - goto out; - } - // A short packet marks the end of the file. - if ((actual_len >= 0) && (actual_len < SEGSIZE)) { - // End of data - close(s); - freeaddrinfo(res); - return result; - } - } else - if (ntohs(hdr->th_opcode) == ERROR) { - *err = ntohs(hdr->th_code); - goto out; - } else { - // What kind of packet is this? - *err = TFTP_PROTOCOL; - goto out; - } - } - } + } else { + recv_len = blksize+sizeof(struct tftphdr); + from_len = sizeof(from_addr); + if ((data_len = recvfrom(s, data, recv_len, 0, + &from_addr, &from_len)) < 0) { + // What happened? + *err = TFTP_NETERR; + goto out; + } +#ifdef CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET + if (ntohs(hdr->th_opcode) == OACK) { + // We can have only *one* option, the one we sent.. + if (strncmp(data+2, "blksize", data_len)==0) { + blksize=atol(data+2+strlen("blksize")+1); + } else { + // option ignored, use default. + } + // Send out the ACK + hdr->th_opcode = htons(ACK); + hdr->th_block = htons(last_good_block); + if (sendto(s, data, 4 /* FIXME */, 0, + &from_addr, from_len) < 0) { + // Problem sending request + *err = TFTP_NETERR; + goto out; + } + } else +#endif + if (ntohs(hdr->th_opcode) == DATA) { + actual_len = 0; + if (ntohs(hdr->th_block) == (last_good_block+1)) { + // Consume this data + cp = hdr->th_data; + data_len -= 4; /* Sizeof TFTP header */ + actual_len = data_len; + result += actual_len; + if (lenth_opcode = htons(ACK); + hdr->th_block = htons(last_good_block); + if (sendto(s, data, 4 /* FIXME */, 0, + &from_addr, from_len) < 0) { + // Problem sending request + *err = TFTP_NETERR; + goto out; + } + // A short packet marks the end of the file. + /* 4 = Sizeof TFTP header */ + if ((actual_len >= 0) && (actual_len < blksize)) { + // End of data + close(s); + freeaddrinfo(res); + return result; + } + } else + if (ntohs(hdr->th_opcode) == ERROR) { + *err = ntohs(hdr->th_code); + goto out; + } else { + // What kind of packet is this? + *err = TFTP_PROTOCOL; + goto out; + } + } + } } // If we got here, it means there was a problem connecting to the // server. Try the next address returned by getaddrinfo nextaddr: if (-1 != s) { - close(s); + close(s); } addrinfo=addrinfo->ai_next; } @@ -289,6 +327,52 @@ int tftp_client_get(char *filename, freeaddrinfo(res); return -1; } + + +int tftp_client_get(const char * const filename, + const char * const server, + const int port, + char *buf, + int len, + const int mode, + int * const err) { + int result; +#ifdef CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET + char *data = malloc(CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET_SIZE+ + sizeof(struct tftphdr)); + if (data==NULL) { + *err=TFTP_ENOSPACE; + return -1; + } +#else + char data[SEGSIZE+sizeof(struct tftphdr)]; +#endif + result=tftp_client_get_inner(data, filename, server, + port, buf, len, mode, err +#ifdef CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET + ,1 +#endif + ); + if (result<0) + { +#ifdef CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET + // try without negotiating packet size. The serves that do + // not support options negotiation may or may not ignore the + // options. If they return an error in the case of options + // this code path will try without packet size negotiation. + result=tftp_client_get_inner(data, filename, server, + port, buf, len, mode, err, + 0); +#endif + } + +#ifdef CYGPKG_NET_TFTPD_CLIENT_BIG_PACKET + free(data); +#endif + + return result; +} + // // Read a file from a host into a local buffer. Returns the // number of bytes actually read, or (-1) if an error occurs. @@ -296,19 +380,19 @@ int tftp_client_get(char *filename, // // Depreciated. Use tftp_client_get instead. int -tftp_get(char *filename, - struct sockaddr_in *server, +tftp_get(const char * const filename, + const struct sockaddr_in * const server, char *buf, int len, - int mode, - int *err) + const int mode, + int * const err) { char server_name[20]; char *ret; int port; ret = inet_ntop(AF_INET, (void *)&server->sin_addr, - server_name, sizeof(server_name)); + server_name, sizeof(server_name)); if (NULL == ret) { *err = TFTP_NETERR; return -1; @@ -322,19 +406,19 @@ tftp_get(char *filename, // Send data to a file on a server via TFTP. // int -tftp_put(char *filename, - struct sockaddr_in *server, - char *buf, +tftp_put(const char * const filename, + const struct sockaddr_in * const server, + const char *buf, int len, - int mode, - int *err) + const int mode, + int * const err) { char server_name[20]; char *ret; int port; ret = inet_ntop(AF_INET, (void *)&server->sin_addr, - server_name, sizeof(server_name)); + server_name, sizeof(server_name)); if (NULL == ret) { *err = TFTP_NETERR; return -1; @@ -350,13 +434,13 @@ tftp_put(char *filename, // On error, *err will hold the reason. // This version uses the server name. This can be a name for DNS lookup // or a dotty or colony number format for IPv4 or IPv6. -int tftp_client_put(char *filename, - char *server, - int port, - char *buf, - int len, - int mode, - int *err) { +int tftp_client_put(const char * const filename, + const char * const server, + const int port, + const char *buf, + int len, + const int mode, + int * const err) { int result = 0; int s = -1, actual_len, data_len; @@ -365,7 +449,8 @@ int tftp_client_put(char *filename, struct sockaddr local_addr, from_addr; char data[SEGSIZE+sizeof(struct tftphdr)]; struct tftphdr *hdr = (struct tftphdr *)data; - char *cp, *fp, *sfp; + const char *fp, *sfp; + char *cp; struct timeval timeout; unsigned short last_good_block = 0; fd_set fds; @@ -388,177 +473,177 @@ int tftp_client_put(char *filename, addrinfo = res; while (addrinfo) { s = socket(addrinfo->ai_family, addrinfo->ai_socktype, - addrinfo->ai_protocol); + addrinfo->ai_protocol); if (s >= 0) { - memcpy(&local_addr,addrinfo->ai_addr,addrinfo->ai_addrlen); - switch(addrinfo->ai_addr->sa_family) { - case AF_INET: { - struct sockaddr_in * saddr = - (struct sockaddr_in *) addrinfo->ai_addr; - struct sockaddr_in * laddr = - (struct sockaddr_in *) &local_addr; - if (port) { - saddr->sin_port = htons(port); - } - laddr->sin_port = htons(put_port++); - laddr->sin_addr.s_addr = INADDR_ANY; - break; - } + memcpy(&local_addr,addrinfo->ai_addr,addrinfo->ai_addrlen); + switch(addrinfo->ai_addr->sa_family) { + case AF_INET: { + struct sockaddr_in * saddr = + (struct sockaddr_in *) addrinfo->ai_addr; + struct sockaddr_in * laddr = + (struct sockaddr_in *) &local_addr; + if (port) { + saddr->sin_port = htons(port); + } + laddr->sin_port = htons(put_port++); + laddr->sin_addr.s_addr = INADDR_ANY; + break; + } #ifdef CYGPKG_NET_INET6 - case AF_INET6: { - struct sockaddr_in6 * saddr = - (struct sockaddr_in6 *) addrinfo->ai_addr; - struct sockaddr_in6 * laddr = - (struct sockaddr_in6 *) &local_addr; - if (port) { - saddr->sin6_port = htons(port); - } - laddr->sin6_port = htons(put_port++); - laddr->sin6_addr = in6addr_any; - break; - } + case AF_INET6: { + struct sockaddr_in6 * saddr = + (struct sockaddr_in6 *) addrinfo->ai_addr; + struct sockaddr_in6 * laddr = + (struct sockaddr_in6 *) &local_addr; + if (port) { + saddr->sin6_port = htons(port); + } + laddr->sin6_port = htons(put_port++); + laddr->sin6_addr = in6addr_any; + break; + } #endif - default: - *err = TFTP_NETERR; - goto out; - } - if (bind(s, - (struct sockaddr *)&local_addr, - addrinfo->ai_addrlen) < 0) { - // Problem setting up my end - *err = TFTP_NETERR; - goto out; - } + default: + *err = TFTP_NETERR; + goto out; + } + if (bind(s, + (struct sockaddr *)&local_addr, + addrinfo->ai_addrlen) < 0) { + // Problem setting up my end + *err = TFTP_NETERR; + goto out; + } - while (1) { - // Create initial request - hdr->th_opcode = htons(WRQ); // Create/write file - cp = (char *)&hdr->th_stuff; - fp = filename; - while (*fp) *cp++ = *fp++; - *cp++ = '\0'; - if (mode == TFTP_NETASCII) { + while (1) { + // Create initial request + hdr->th_opcode = htons(WRQ); // Create/write file + cp = (char *)&hdr->th_stuff; + fp = filename; + while (*fp) *cp++ = *fp++; + *cp++ = '\0'; + if (mode == TFTP_NETASCII) { fp = "NETASCII"; - } else if (mode == TFTP_OCTET) { + } else if (mode == TFTP_OCTET) { fp = "OCTET"; - } else { + } else { *err = TFTP_INVALID; - goto out; - } - while (*fp) *cp++ = *fp++; - *cp++ = '\0'; - // Send request - if (sendto(s, data, (int)(cp-data), 0, - addrinfo->ai_addr, - addrinfo->ai_addrlen) < 0) { + goto out; + } + while (*fp) *cp++ = *fp++; + *cp++ = '\0'; + // Send request + if (sendto(s, data, (int)(cp-data), 0, + addrinfo->ai_addr, + addrinfo->ai_addrlen) < 0) { // Problem sending request *err = TFTP_NETERR; - goto nextaddr; - } - // Wait for ACK - timeout.tv_sec = TFTP_TIMEOUT_PERIOD; - timeout.tv_usec = 0; - FD_ZERO(&fds); - FD_SET(s, &fds); - if (select(s+1, &fds, 0, 0, &timeout) <= 0) { + goto nextaddr; + } + // Wait for ACK + timeout.tv_sec = TFTP_TIMEOUT_PERIOD; + timeout.tv_usec = 0; + FD_ZERO(&fds); + FD_SET(s, &fds); + if (select(s+1, &fds, 0, 0, &timeout) <= 0) { if (++total_timeouts > TFTP_RETRIES_MAX) { - // Timeout - no ACK received - *err = TFTP_TIMEOUT; - goto nextaddr; + // Timeout - no ACK received + *err = TFTP_TIMEOUT; + goto nextaddr; } - } else { + } else { recv_len = sizeof(data); from_len = sizeof(from_addr); if ((data_len = recvfrom(s, &data, recv_len, 0, &from_addr, &from_len)) < 0) { - // What happened? - *err = TFTP_NETERR; - goto out; + // What happened? + *err = TFTP_NETERR; + goto out; } if (ntohs(hdr->th_opcode) == ACK) { - // Write request accepted - start sending data - break; + // Write request accepted - start sending data + break; } else - if (ntohs(hdr->th_opcode) == ERROR) { + if (ntohs(hdr->th_opcode) == ERROR) { *err = ntohs(hdr->th_code); goto out; - } else { + } else { // What kind of packet is this? - goto out; - } - } - } - - // Send data - sfp = buf; - last_good_block = 1; - while (result < len) { - // Build packet of data to send - data_len = min(SEGSIZE, len-result); - hdr->th_opcode = htons(DATA); - hdr->th_block = htons(last_good_block); - cp = hdr->th_data; - fp = sfp; - actual_len = data_len + 4; - // FIXME - what about "netascii" data? - while (data_len-- > 0) *cp++ = *fp++; - // Send data packet - if (sendto(s, data, actual_len, 0, - &from_addr, from_len) < 0) { + goto out; + } + } + } + + // Send data + sfp = buf; + last_good_block = 1; + while (result < len) { + // Build packet of data to send + data_len = min(SEGSIZE, len-result); + hdr->th_opcode = htons(DATA); + hdr->th_block = htons(last_good_block); + cp = hdr->th_data; + fp = sfp; + actual_len = data_len + 4; + // FIXME - what about "netascii" data? + while (data_len-- > 0) *cp++ = *fp++; + // Send data packet + if (sendto(s, data, actual_len, 0, + &from_addr, from_len) < 0) { // Problem sending request *err = TFTP_NETERR; - goto out; - } - // Wait for ACK - timeout.tv_sec = TFTP_TIMEOUT_PERIOD; - timeout.tv_usec = 0; - FD_ZERO(&fds); - FD_SET(s, &fds); - if (select(s+1, &fds, 0, 0, &timeout) <= 0) { + goto out; + } + // Wait for ACK + timeout.tv_sec = TFTP_TIMEOUT_PERIOD; + timeout.tv_usec = 0; + FD_ZERO(&fds); + FD_SET(s, &fds); + if (select(s+1, &fds, 0, 0, &timeout) <= 0) { if (++total_timeouts > TFTP_TIMEOUT_MAX) { - // Timeout - no data received - *err = TFTP_TIMEOUT; - goto out; + // Timeout - no data received + *err = TFTP_TIMEOUT; + goto out; } - } else { + } else { recv_len = sizeof(data); from_len = sizeof(from_addr); if ((data_len = recvfrom(s, &data, recv_len, 0, &from_addr, &from_len)) < 0) { - // What happened? - *err = TFTP_NETERR; - goto out; + // What happened? + *err = TFTP_NETERR; + goto out; } if (ntohs(hdr->th_opcode) == ACK) { - if (ntohs(hdr->th_block) == last_good_block) { - // Advance pointers, etc - sfp = fp; - result += (actual_len - 4); - last_good_block++; - } else { - diag_printf("Send block #%d, got ACK for #%d\n", - last_good_block, ntohs(hdr->th_block)); - } + if (ntohs(hdr->th_block) == last_good_block) { + // Advance pointers, etc + sfp = fp; + result += (actual_len - 4); + last_good_block++; + } else { + diag_printf("Send block #%d, got ACK for #%d\n", + last_good_block, ntohs(hdr->th_block)); + } } else - if (ntohs(hdr->th_opcode) == ERROR) { + if (ntohs(hdr->th_opcode) == ERROR) { *err = ntohs(hdr->th_code); goto out; - } else { + } else { // What kind of packet is this? *err = TFTP_PROTOCOL; - goto out; - } - } - } - close (s); - return result; + goto out; + } + } + } + close (s); + return result; } // If we got here, it means there was a problem connecting to the // server. Try the next address returned by getaddrinfo nextaddr: if (-1 != s) { - close(s); + close(s); } addrinfo=addrinfo->ai_next; }