上一讲中了解了tftp的原理和代码的具体实现之后,这一讲具体对uboot客户端环境下的tftp升级进行说明。与之前自己实现的tftp客户端不同的是,uboot中还没有实现创建udp的接口,只是通过将传输信息必要的信息放入一定的字符数组位置中,然后将该字符数组放入网卡的发送缓冲区中,由网卡实现数据解析和发送。
接下来就uboot的tftp客户端实现和uboot怎么发送传输和升级进度进行详细的说明。
uboot的tftp客户端实现
int cmd_tftp(int argc, char *argv[])
{
...
tftp:
if (net_tftp(ac, buf, byte_count, fname)) //调用net_tftp接口
return ERR_OK;
else
return ERR_FILE;
...
}
int net_tftp(int put, unsigned long dest_address, unsigned int bytecount, char *file)
{
img.addr = dest_address;
img.count = bytecount;
printf("tftp %s %s:%s \n", (put ? "put" : "get"),
inet_ntoa(&bootvars.server), file);
return ((tftp(file, (put ? upload_file : download_file)))? 1 : 0); //调用tftp接口
}
//uboot中具体实现tftp客户端的接口
int tftp(const char *name, int (*func) (unsigned char *, int, int, int))
{
static unsigned short iport = 2000;
unsigned short oport, len, block = 0, prevblock = 0, txblk = 0;
int bcounter = 0, retry = 0, timeout, result;
struct tftp_t *tr;
struct nbuf *pkt;
int packetsize = TFTP_DEFAULTSIZE_PACKET; //和前一章说明的一样,这里的数据包限定完整长度为TFTP_DEFAULTSIZE_PACKET,即512字节
unsigned long server = bootvars.server; //全局变量,这里表示的是uboot环境变量中设置的服务器IP
unsigned long data;
short put = (func == upload_file); //这里的put变量用于后续区分执行是上传文件还是下载文件
await_reply(AWAIT_QDRAIN, 0, 0);
tp.opcode = put ? htons(TFTP_WRQ) : htons(TFTP_RRQ); //前面讲过,TFTP_WRQ和TFTP_RRQ分别表示的是tftp协议中开始处的请求上传及请求下载选项
len = 1 + sizeof (tp.ip) + sizeof (tp.udp) + //发送必要信息:发送的总数据长度
sizeof (tp.opcode) + sprintf((char *) tp.u.rrq, "%s%coctet", name, 0);
//!!!
if (0 == udp_tx(server, ++iport, TFTP_PORT, len, &tp)) //!!!发现这里通过udp_tx进行信息发送,必要的发送信息包括:服务器地址,发送端口号,TFTP接收端端口号(69)以及发送信息;
return (0);
//在发送完上传请求或者下载请求后,进入接收服务器返回的信息并处理阶段
while (1)
{
timeout = rfc951_sleep(block ? TFTP_REXMT : TIMEOUT, retry);
data = (unsigned long) iport;
result = await_reply(AWAIT_TFTP, &data, timeout);
if (ESC == result)
return 0;
//超时,进入重发机制
if (0 == result)
{
if (!block && (MAX_TFTP_RETRIES > retry++))
{
if (0 == udp_tx(server, ++iport, TFTP_PORT, len, &tp))