U-boot的TFTP流程分析
转载请注明出处: http://www.cnblogs.com/gngshn/p/4512318.html
1 /**** u-boot的网卡注册流程 ****/ 2 int eth_initialize(gd->bd); //eth.c 3 eth_devices = NULL; eth_current = NULL; 4 void eth_env_init(gd->bd); //eth.c 5 //BootFile[]=CONFIG_BOOTFILE; //net.c 6 int cpu_eth_init(gd->bd); //cpu.c 7 int rtl8168_initialize(gd->bd); //rtl8168.c 8 struct eth_device *dev; //rtl8168.c 9 dev = (struct eth_device *)malloc(sizeof *dev); 10 memset(dev, 0, sizeof(*dev)); 11 tp = (struct rtl8168_private *)malloc(sizeof *tp); 12 memset(tp, 0, sizeof(*tp)); 13 tp->mmio_addr = pci_mem_to_phys(devno, iobase); //0xb8400000 14 tp->devno = devno; 15 tp->dev = dev; 16 tp->rx_buf_sz = RX_BUF_SIZE; 17 rtl8168_get_mac_version(tp, tp->mmio_addr); 18 sprintf(dev->name, "r8168#%d", card_number); //dev->name[]=r8168#0; 19 rtl8168_get_mac_address(tp); 20 tp->chipset = i; 21 dev->priv = (void *)tp; 22 dev->iobase = (int)tp->mmio_addr; //0xb8400000 23 dev->init = rtl8168_init; 24 dev->halt = rtl8168_halt; 25 dev->send = rtl8168_send; 26 dev->recv = rtl8168_recv; 27 int eth_register (dev); //eth.c 28 eth_current = eth_devices = dev; 29 void eth_current_changed(); //eth.c 30 setenv("ethact", eth_current->name); 31 return; 32 dev->state = ETH_STATE_INIT; 33 dev->next = eth_devices; 34 dev->index = index++; //index=0; 35 return 0; 36 card_number++; //=1 37 return card_number; 38 return card_number; 39 int eth_write_hwaddr(dev, "eth", dev->index); //eth.c 40 unsigned char env_enetaddr[6]; 41 int eth_getenv_enetaddr_by_index("eth", dev->index, env_netaddr); //eth.c 42 int eth_getenv_enetaddr("ethaddr", env_netaddr); //eth.c 43 void eth_parse_enetaddr(getenv("ethaddr"), env_netaddr); //("DE:AD:BE:EF:01:02", env_netaddr) 44 //env_netaddr[6]={0xde, 0xad, 0xbe, 0xef, 0x01, 0x02}; 45 inline int is_valid_ether_addr(env_netaddr); //判断是否为有效MAC地址 46 return 1; 47 return 1; 48 memcpy(dev->enetaddr, env_enetaddr, 6); 49 return 0; 50 void eth_current_changed(); //eth.c 51 return 1; 52 /**** u-boot的网卡注册流程结束 ****/ 53 54 55 56 /**** TFTP调用流程 ****/ 57 int do_tftpb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); //cmd_net.c 58 int netboot_common(TFTPGET, cmdtp, argc, argv); //cmd_net.c 59 load_addr = simple_strtoul(argv[1], NULL, 16); 60 copy_filename(BootFile, argv[2], sizeof(BootFile)); //BootFile[]=argv[2];BootFile在net.c中 61 size = int NetLoop(TFTP); //net.c 62 void net_init(); //net.c 63 /**** 第一次调用时运行begin ****/ 64 NetTxPacket = &PktBuf[0] + (128 - 1); //其中PktBuf的定义如下 65 //这是一个全局变量 static uchar PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];在net.c中 66 //这是一个全局变量 static uchar PktBuf[(4+1)*1536+128]; 67 NetTxPacket -= (ulong)NetTxPacket % PKTALIGN; //对齐 68 for (i = 0; i < PKTBUFSRX; i++) 69 NetRxPackets[i] = NetTxPacket + (i + 1) * PKTSIZE_ALIGN; 70 //uchar *NetRxPackets[PKTBUFSRX];在net.c中 71 void ArpInit(); //arp.c 72 NetArpWaitPacketMAC = NULL; 73 NetArpWaitPacketIP = 0; 74 NetArpWaitReplyIP = 0; 75 NetArpWaitTxPacketSize = 0; 76 NetArpTxPacket = &NetArpPacketBuf[0] + (PKTALIGN - 1); 77 NetArpTxPacket -= (ulong)NetArpTxPacket % PKTALIGN; 78 //将NetArpPacketBuf对齐到PKTALIGN 79 return; 80 void net_clear_handlers(); //net.c 81 net_set_udp_handler(NULL); 82 net_set_arp_handler(NULL); 83 NetSetTimeout(0, NULL); 84 return; 85 /**** 第一次调用时运行end ****/ 86 void NetInitLoop(); //net.c 87 /**** 第一次调用时运行begin ****/ 88 NetOurIP = getenv_IPaddr("ipaddr"); //"192.168.1.26" 89 NetOurGatewayIP = getenv_IPaddr("gatewayip"); //"192.168.1.1" 90 NetOurSubnetMask = getenv_IPaddr("netmask"); //"255.255.255.0" 91 NetServerIP = getenv_IPaddr("serverip"); //"192.168.1.50" 92 NetOurNativeVLAN = NULL; 93 NetOurVLAN = NULL; 94 /**** 第一次调用时运行end ****/ 95 memcpy(NetOurEther, eth_get_dev()->enetaddr, 6); //NetOurEther[6]="DE:AD:BE:EF:01:02" 96 return; 97 return; 98 void eth_halt(); 99 eth_current->halt(eth_current); //eth.c: 调用rtl8168_halt 100 return; 101 void eth_set_current(); //eth.c 102 int eth_init(gd->bd); //eth.c 103 eth_current->init(eth_current, gd->bd); //调用rtl8168_init 104 //如果初始化成功 105 eth_current->state = ETH_STATE_ACTIVE; 106 return 0; 107 start: 108 inline void net_set_state(NETLOOP_CONTINUE); //net.h 109 void NetInitLoop(); //net.c:运行过程在上面有, 不再展开, 此时不再是第一次调用 110 int net_check_prereq(TFTP); //net.c 111 return 0; //检查了ourip, serverip, MAC地址 112 void TftpStart(TFTP); //tftp.c 113 //首先设置tftpblocksize和tftptimeout先查看环境变量, 如果没有就使用默认值 114 TftpRemoteIP = NetServerIP; //"192.168.1.50" 115 strncpy(tftp_filename, BootFile, MAX_LEN); 116 tftp_filename[MAX_LEN-1] = 0; //tftp_filename[]=BootFile[]; 117 TftpState = STATE_SEND_RRQ; //发送接收请求包 118 time_start = get_timer(0); //arch/rlx/cpu/time.c, 设置CPU的COUNT, COMPARE? 119 TftpTimeoutCountMax = TftpRRQTimeoutCountMax; 120 void NetSetTimeout(TftpTimeoutMSecs, TftpTimeout); //(5000, TftpTimeout), net.c中 121 //TftpTimeout()函数在TFTP超时后打印T, 当超时的次数到达TftpTimeoutCountMax时, 重启网卡 122 timeHandler = tftptimeout; 123 timeStart = get_timer(0); //? 124 timeDelta = iv * CONFIG_SYS_HZ / 1000; 125 void net_set_udp_handler(TftpHandler); //net.c 126 //TftpHandler()函数用于接收tftp数据 127 static rxhand_f *udp_packet_handler = TftpHandler; //设置接收handler 128 TftpRemotePort = WELL_KNOWN_PORT; //69 129 TftpTimeoutCount = 0; 130 TftpOurPort = 1024 + (get_timer(0) % 3072); //设置随机端口号 131 TftpBlock = 0; 132 memset(NetServerEther, 0, 6); //清零severMAC, 将使用ARP获取 net/net.c:142:uchar NetServerEther[6]; 133 TftpBlkSize = TFTP_BLOCK_SIZE; 134 void TftpSend(); //tftp.c, 发送TFTP包, 这里分析的是发送RRQ包的流程 135 uchar *pkt; 136 uchar *xp; 137 int len = 0; 138 ushort *s; 139 pkt = NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE; //pkt+以太网的头大小+ip头大小+udp头大小, 留下以太网, ip头, udp头的位置 140 /**** 开始填写TFTP-RRQ包 ****/ 141 xp = pkt; 142 s = (ushort *)pkt; 143 *s++ = htons(TFTP_RRQ); 144 pkt = (uchar *)s; 145 strcpy((char *)pkt, tftp_filename); 146 pkt += strlen(tftp_filename) + 1; 147 strcpy((char *)pkt, "octet"); 148 pkt += 5 /*strlen("octet")*/ + 1; 149 strcpy((char *)pkt, "timeout"); 150 pkt += 7 /*strlen("timeout")*/ + 1; 151 sprintf((char *)pkt, "%lu", TftpTimeoutMSecs / 1000); 152 pkt += strlen((char *)pkt) + 1; 153 pkt += sprintf((char *)pkt, "blksize%c%d%c", 0, TftpBlkSizeOption, 0); 154 len = pkt - xp; //RRQ包的大小 155 /**** TFTP-RRQ包填写完成 ****/ 156 /* TFTP的RRQ包组成 optcode有两个字节, 后面的参数都是字符串, 用字符串的结束符\0作为分隔符 157 *----------------------------------------------------------------------------------------------------------------------* 158 * optcode | filename | mode | opt1 | value1 | opt2 | value2 * 159 *----------------------------------------------------------------------------------------------------------------------* 160 * 1 | "zImage" | "octet" | "timeout" | "5" | "blksize" | "1462" * 161 *----------------------------------------------------------------------------------------------------------------------*/ 162 /* TFTP 的发送接收过程如下 163 *----------------------------------------------------------------------* 164 * client server * 165 *----------------------------------------------------------------------* 166 * |1|"zImage"|"octet"|"blksize"|"1412"|"timeout"|"5"| --> * RRQ 167 * <-- |6|"blocksize"|"1412"|"timeout"|"5"| * OACK 168 * |4|0| --> * ACK 169 * <-- |3|1|1412 octets data * DATA 170 * |4|1| --> * ACK 171 * <-- |3|2|1412 octets data * DATA 172 * |4|2| --> * ACK 173 * <-- |3|3|<1412 octets data * DATA 174 * |4|3| --> * ACK 175 *----------------------------------------------------------------------*/ 176 int NetSendUDPPacket(NetServerEther, TftpRemoteIP, TftpRemotePort, TftpOurPort, len); //net.c (0, "192.168.1.50"to ulong, 69, TftpOurPort, len) 177 uchar *pkt; 178 int eth_hdr_size; 179 int pkt_hdr_size; 180 pkt = (uchar *)NetTxPacket; //pkt指向以太网标头 181 eth_hdr_size = NetSetEther(pkt, ether, PROT_IP); //net.c (NetTxPacket, 0, 0x0800), return int 182 /**** 开始填写以太网标头 ****/ 183 struct ethernet_hdr *et = (struct ethernet_hdr *)pkt; //NetTxPacket 184 /**************************************** 185 * struct ethernet_hdr { * 186 * uchar et_dest[6]; * 187 * uchar et_src[6]; * 188 * ushort et_protlen; * 189 * } * 190 ****************************************/ 191 memcpy(et->et_dest, addr, 6); //0 192 memcpy(et->et_src, NetOurEther, 6); 193 et->et_protlen = htons(prot); //PROT_IP 194 /**** 以太网标头填写完成 ****/ 195 return (sizeof(struct ethernet_hdr)); 196 pkt += eth_hdr_size; //pkt指向ip标头 197 void net_set_udp_header(pkt, TftpRemoteIP, TftpRemotePort, TftpOurPort, len); //net.c 198 /**** 开始填写ip标头和udp标头 ****/ 199 /************************************************************************ 200 * struct ip_udp_hdr { * 201 * uchar ip_hl_v; // header length and version * 202 * uchar ip_tos; // type of service * 203 * ushort ip_len; // total length * 204 * ushort ip_id; // identification * 205 * ushort ip_off; // fragment offset field * 206 * uchar ip_ttl; // time to live * 207 * uchar ip_p; // protocol * 208 * ushort ip_sum; // checksum * 209 * IPaddr_t ip_src; // Source IP address * 210 * IPaddr_t ip_dst; // Destination IP address * 211 * ushort udp_src; // UDP source port * 212 * ushort udp_dst; // UDP destination port * 213 * ushort udp_len; // Length of UDP packet * 214 * ushort udp_xsum // Checksum * 215 * }; * 216 ************************************************************************/ 217 struct ip_udp_hdr *ip = (struct ip_udp_hdr *)pkt; 218 if (len & 1) 219 //如果RRQ包大小为奇数, 将最后一个字节后面加入0x00, 这样checksum才能正常工作 220 pkt[IP_UDP_HDR_SIZE + len] = 0; 221 void net_set_ip_header(pkt, TftpRemoteIP, NetOurIP); //net.c 222 struct ip_udp_hdr *ip = (struct ip_udp_hdr *)pkt; 223 ip->ip_hl_v = 0x45; 224 ip->ip_tos = 0; 225 ip->ip_len = htons(IP_HDR_SIZE); //sizeof(struct ip_hdr) 226 ip->ip_id = htons(NetIPID++); //一个全局变量 227 ip->ip_off = htons(IP_FLAGS_DFRAG); //数据不打断的标志 228 ip->ip_ttl = 255; 229 ip->ip_sum = 0; 230 NetCopyIP((void *)&ip->ip_src, &NetOurIP); 231 NetCopyIP((void *)&ip->ip_dst, &TftpRemoteIP); 232 return; 233 ip->ip_len = htons(IP_UDP_HDR_SIZE + len); 234 ip->ip_p = IPPROTO_UDP; 235 ip->ip_sum = ~NetCksum((uchar *)ip, IP_HDR_SIZE >> 1); 236 237 ip->udp_src = htons(sport); 238 ip->udp_dst = htons(dport); 239 ip->udp_len = htons(UDP_HDR_SIZE + len); 240 ip->udp_xsum = 0; 241 /**** ip标头和udp标头填写完成 ****/ 242 /* TFTP 网络包封装完成后的格式如下 243 *----------------------------------------------------------------* 244 * TFTP的网络包整体格式 * 245 *----------------------------------------------------------------* 246 * 以太网标头 | ip标头 | udp标头 | TFTP包 * 247 *----------------------------------------------------------------*/ 248 return 249 pkt_hdr_size = eth_hdr_size + IP_UDP_HDR_SIZE; //sizeof(struct ethernet_hdr) + sizeof(struct ip_udp_hdr); 表示packet的所有标头大小的和 250 if (memcmp(NetServerEther, NetEtherNullAddr, 6) == 0) { 251 //如果没有sever的MAC使用ARP协议获取 252 NetArpWaitPacketIP = dest; //NetServerIP NetArpWaitPacketIP变量在arp.c中 253 NetArpWaitPacketMAC = NetServerEther; //*NetArpWaitPacketMAC = 0x0000000000 NetArpWaitPacketMAC变量在arp.c中 254 NetArpWaitTxPacketSize = pkt_hdr_size + len; //TFTP RRQ整个包的大小 NetArpWaitTxPacketSize变量在arp.c中 255 NetArpWaitTry = 1; //arp.c 256 NetArpWaitTimerStart = get_timer(0); //arp.c 257 void ArpRequest(); //arp.c 258 NetArpWaitReplyIP = NetOurGatewayIP; //如果是在同一个网段中, 且有NetOurGatewayIP 259 //NetArpWaitReplyIP = NetArpWaitPacketIP; 如果在不同网段, 或同网段没有NetOurGatewayIP 260 void arp_raw_request(NetOurIP, NetEtherNullAddr, NetArpWaitReplyIP); //arp.c 261 uchar *pkt; 262 struct arp_hdr *arp; 263 int eth_hdr_size; 264 pkt = NetArpTxPacket; 265 eth_hdr_size = int NetSetEther(pkt, NetBcastAddr, PROT_ARP); //net.c 这个在前面讲过, 用来填写以太网标头 266 //这里 267 /**** 开始填写以太网标头 ****/ 268 struct ethernet_hdr *et = (struct ethernet_hdr *)pkt; //NetTxPacket 269 /**************************************** 270 * struct ethernet_hdr { * 271 * uchar et_dest[6]; * 272 * uchar et_src[6]; * 273 * ushort et_protlen; * 274 * } * 275 ****************************************/ 276 memcpy(et->et_dest, NetBcastAddr, 6); //{0xff, 0xff, 0xff, 0xff, 0xff, 0xff} 广播地址 277 memcpy(et->et_src, NetOurEther, 6); 278 et->et_protlen = htons(prot); //PROT_ARP 279 /**** 以太网标头填写完成 ****/ 280 return (sizeof(struct ethernet_hdr)); 281 pkt += eth_hdr_size; //pkt指向arp标头 282 arp = (struct arp_hdr *) pkt; 283 /**** 开始填写ARP标头 ****/ 284 /******************************************************************************** 285 * struct arp_hdr { * 286 * ushort ar_hrd; //Format of hardware address * 287 * # define ARP_ETHER 1 //Ethernet hardware address * 288 * ushort ar_pro; //Format of protocol address * 289 * uchar ar_hln; //Length of hardware address * 290 * # define ARP_HLEN 6 * 291 * uchar ar_pln; //Length of protocol address * 292 * # define ARP_PLEN 4 * 293 * ushort ar_op; //Operation * 294 * # define ARPOP_REQUEST 1 //Request to resolve address * 295 * # define ARPOP_REPLY 2 //Response to previous request * 296 * * 297 * # define RARPOP_REQUEST 3 //Request to resolve address * 298 * # define RARPOP_REPLY 4 //Response to previous request * 299 * * 300 * * 301 * * The remaining fields are variable in size, according to * 302 * * the sizes above, and are defined as appropriate for * 303 * * specific hardware/protocol combinations. * 304 * * 305 * uchar ar_data[0]; * 306 * #define ar_sha ar_data[0] * 307 * #define ar_spa ar_data[ARP_HLEN] * 308 * #define ar_tha ar_data[ARP_HLEN + ARP_PLEN] * 309 * #define ar_tpa ar_data[ARP_HLEN + ARP_PLEN + ARP_HLEN] * 310 * #if 0 * 311 * uchar ar_sha[]; //Sender hardware address * 312 * uchar ar_spa[]; //Sender protocol address * 313 * uchar ar_tha[]; //Target hardware address * 314 * uchar ar_tpa[]; //Target protocol address * 315 * #endif //0 * 316 * }; * 317 *********************************************************************************/ 318 arp->ar_hrd = htons(ARP_ETHER); 319 arp->ar_pro = htons(PROT_IP); 320 arp->ar_hln = ARP_HLEN; 321 arp->ar_pln = ARP_PLEN; 322 arp->ar_op = htons(ARPOP_REQUEST); 323 memcpy(&arp->ar_sha, NetOurEther, ARP_HLEN); 324 NetWriteIP(&arp->ar_spa, NetOurIP); 325 memcpy(&arp->ar_tha, NetEtherNullAddr, ARP_HLEN); 326 NetWriteIP(&arp->ar_tpa, NetArpWaitReplyIP); 327 /**** ARP标头填写完成 ****/ 328 inline void NetSendPacket(NetArpTxPacket, eth_hdr_size + ARP_HDR_SIZE); //net.h 发送包 329 //NetArpTxPacket在ArpInit()中进行的赋值 330 (void) int eth_send(NetArpTxPacket, eth_hdr_size + ARP_HDR_SIZE); //eth.c 331 return int eth_current->send(eth_current, NetArpTxPacket, eth_hdr_size + ARP_HDR_SIZE); 332 //调用rtl8168_send 333 struct rtl8168_private *tp = (struct rtl8168_private *)dev->priv; 334 phys_addr_t ioaddr = tp->mmio_addr; //0xb8400000 335 u32 to, len = eth_hdr_size + ARP_HDR_SIZE; 336 int ret, cur_tx = 0; 337 cur_tx = tp->cur_tx; //下一个要被发送的数据包描述符数组的index 338 tp->TxDescArray[cur_tx].addr = cpu_to_le64(bus_to_phys(NetArpTxPacket)); 339 if (cur_tx == (NUM_TX_DESC - 1)) { //16-1 340 tp->TxDescArray[cur_tx].opts1 = 341 cpu_to_le32((DescOwn | RingEnd | FirstFrag | LastFrag) | 342 ((len > ETH_ZLEN) ? len : ETH_ZLEN)); 343 } else { 344 tp->TxDescArray[cur_tx].opts1 = 345 cpu_to_le32((DescOwn | FirstFrag | LastFrag) | 346 ((len > ETH_ZLEN) ? len : ETH_ZLEN)); 347 } 348 wmb(); 349 flush_cache((unsigned long)&tp->TxDescArray[cur_tx], sizeof(struct TxDesc)); 350 flush_cache((unsigned long)packet, length); 351 RTL_W8(TxPoll, NPQ); 352 //这里为什么要继续加1? 353 tp->cur_tx = (cur_tx+1) % NUM_TX_DESC; 354 to = currticks() + TX_TIMEOUT; 355 do { 356 flush_cache((unsigned long)&tp->TxDescArray[cur_tx], sizeof(struct TxDesc)); 357 RTL_W8(TxPoll, NPQ); 358 } while ((le32_to_cpu(tp->TxDescArray[cur_tx].opts1) & DescOwn)&& (currticks() < to)); 359 if (currticks() >= to) { 360 ret = 0; 361 } else { 362 ret = length; 363 } 364 udelay(20); 365 return ret; 366 //前面写的是return int xxx(); 367 return; 368 return; 369 return; 370 //if语句缩进补充 371 return 1; 372 } else { 373 //发送packet 374 NetSendPacket(NetTxPacket, pkt_hdr_size + len); //eth.h 375 (void) int eth_send(NetTxPacket, pkt_hdr_size + len); //eth.c 376 return eth_current->send(eth_current, NetTxPacket, pkt_hdr_size + len); //调用rtl8168_send 377 return; 378 //if语句缩进补充 379 return 0; 380 } 381 return; 382 return; 383 for (;;) { 384 WATCHDOG_RESET(); //我们应该是没有开启WATCHDOG 385 eth_rx(); //eth.c 接收文件关键一步 386 return int eth_current->recv(eth_current); //调用rtl8168_recv 387 //略去硬件代码 388 void NetReceive(tp->RxBufferRing[cur_rx], length); //net.c, 第一个参数是接收到的packet的位置, 第二个参数是packet的大小 389 struct ethernet_hdr *et; 390 struct ip_udp_hdr *ip; 391 IPaddr_t dst_ip; 392 IPaddr_t src_ip; 393 int eth_proto; 394 ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid; 395 NetRxPacket = tp->RxBufferRing[cur_rx]; 396 NetRxPacketLen = len; 397 et = (struct ethernet_hdr *)tp->RxBufferRing[cur_rx]; 398 eth_proto = ntohs(et->et_protlen); 399 ip = (struct ip_udp_hdr *)(tp->RxBufferRing[cur_rx] + ETHER_HDR_SIZE); 400 len -= ETHER_HDR_SIZE; 401 switch (eth_proto) { 402 case PROT_ARP: //接收的是ARP包 403 void ArpReceive(et, ip, len); //arp.c 404 struct arp_hdr *arp; 405 IPaddr_t reply_ip_addr; 406 uchar *pkt; 407 int eth_hdr_size; 408 arp = (struct arp_hdr *)ip; 409 //检查这个arp包是否是自己需要接收的那个arp reply包 410 if (ntohs(arp->ar_hrd) != ARP_ETHER) 411 //if语句缩进补充 412 return; 413 if (ntohs(arp->ar_pro) != PROT_IP) 414 //if语句缩进补充 415 return; 416 if (arp->ar_hln != ARP_HLEN) 417 //if语句缩进补充 418 return; 419 if (arp->ar_pln != ARP_PLEN) 420 //if语句缩进补充 421 return; 422 if (NetOurIP == 0) 423 //if语句缩进补充 424 return; 425 if (NetReadIP(&arp->ar_tpa) != NetOurIP) //tpa: target protocol address(IP) 426 //if语句缩进补充 427 return; 428 switch (ntohs(arp->ar_op)) { 429 case ARPOP_REQUEST: 430 pkt = (uchar *)et; 431 eth_hdr_size = net_update_ether(et, et->et_src, PROT_ARP); 432 pkt += eth_hdr_size; 433 arp->ar_op = htons(ARPOP_REPLY); 434 memcpy(&arp->ar_tha, &arp->ar_sha, ARP_HLEN); //tha: target hardware address(MAC) 435 NetCopyIP(&arp->ar_tpa, &arp->ar_spa); //tpa: target protocol address(IP) 436 memcpy(&arp->ar_sha, NetOurEther, ARP_HLEN); //sha: sender hardware address(MAC) 437 NetCopyIP(&arp->ar_spa, &NetOurIP); //spa: sender protocol address(IP) 438 //回应主机的arp request(把sender和target对调, 填入自己的MAC, 然后发送) 439 inline void NetSendPacket((uchar *)et, eth_hdr_size + ARP_HDR_SIZE); 440 (void) int eth_send(NetTxPacket, pkt_hdr_size + len); //eth.c 441 return eth_current->send(eth_current, NetTxPacket, pkt_hdr_size + len); //调用rtl8168_send 442 return; 443 //switch语句补充缩进 444 return; 445 case ARPOP_REPLY: 446 reply_ip_addr = NetReadIP(&arp->ar_spa); 447 memcpy(NetArpWaitPacketMAC,&arp->ar_sha, ARP_HLEN); 448 rxhand_f *net_get_arp_handler()((uchar *)arp, 0, reply_ip_addr, 0, len); //函数指针调用函数 449 // 此处net_get_arp_handler() = return arp_packet_handler; 450 //TODO XXX 此处arp_packet_handler在哪里进行了设置????, 调用NULL指针不会跑飞了? 451 memcpy(((struct ethernet_hdr *)NetTxPacket)->et_dest, &arp->ar_sha, ARP_HLEN); //填入主机的MAC地址 452 inline void NetSendPacket(NetTxPacket, NetArpWaitTxPacketSize); //将之前的填写好的TFTP数据包发送 453 (void) int eth_send(NetTxPacket, pkt_hdr_size + len); //eth.c 454 return eth_current->send(eth_current, NetTxPacket, pkt_hdr_size + len); //调用rtl8168_send 455 return; 456 NetArpWaitPacketIP = 0; 457 NetArpWaitTxPacketSize = 0; 458 NetArpWaitPacketMAC = NULL; 459 //switch语句补充缩进 460 return; 461 break; 462 case PROT_IP://接收的是IP(TFTP)包 463 len = ntohs(ip->ip_len); 464 // Can't deal with anything except IPv4 465 if ((ip->ip_hl_v & 0xf0) != 0x40) 466 //if语句缩进补充 467 return; 468 // Can't deal with IP options (headers != 20 bytes) 469 if ((ip->ip_hl_v & 0x0f) > 0x05) 470 //if语句缩进补充 471 return; 472 // Check the Checksum of the header 473 if (!NetCksumOk((uchar *)ip, IP_HDR_SIZE / 2)) { 474 //if语句缩进补充 475 return; 476 } 477 /* If it is not for us, ignore it */ 478 dst_ip = NetReadIP(&ip->ip_dst); 479 if (NetOurIP && dst_ip != NetOurIP && dst_ip != 0xFFFFFFFF) { 480 //if语句缩进补充 481 return; 482 } 483 //检查数据头的合理性完成 484 src_ip = NetReadIP(&ip->ip_src); 485 ip = NetDefragment(ip, &len); 486 //TODO 分析与代码分段相关的内容 487 if (!ip) { 488 //if语句缩进补充 489 return; 490 } 491 (*udp_packet_handler)((uchar *)ip + IP_UDP_HDR_SIZE, ntohs(ip->udp_dst), src_ip, ntohs(ip->udp_src), 492 ntohs(ip->udp_len) - UDP_HDR_SIZE); 493 //udp_packet_handler = TftpHandler 494 //这里的dst和src是相对TFTP数据的方向来说的, 此处src为Server, dst为本机 495 //voidTftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len) 496 //@1:UDP数据内容的指针, @2: dst端口(本机), @3: src ip(Server), @4: src端口(Sever), @5: UDP表中的TFTP包大小 497 void TftpHandler((uchar *)ip + IP_UDP_HDR_SIZE, ntohs(ip->udp_dst), src_ip, ntohs(ip->udp_src), 498 ntohs(ip->udp_len) - UDP_HDR_SIZE); //tftp.c 499 __be16 proto; 500 __be16 *s; 501 int i; 502 if (dest != TftpOurPort) { 503 //if缩进补充 504 return; 505 } 506 if (TftpState != STATE_SEND_RRQ && src != TftpRemotePort && 507 TftpState != STATE_RECV_WRQ && TftpState != STATE_SEND_WRQ) { 508 //如果不是在读发送RRQ, WRQ, 不是在接收WRQ并且ip地址不是Severip就返回 509 //if缩进补充 510 return; 511 } 512 len -= 2; 513 s = (__be16 *)pkt; 514 proto = *s++; 515 pkt = (uchar *)s; 516 // proto指向TFTP的optcode, pkt指向移除optcode后面部分的开始 517 switch (ntohs(proto)) { 518 case TFTP_RRQ: 519 //switch语句缩进补充 520 return; 521 case TFTP_OACK: 522 //收到主机的RRQ相应信号OACK, 此时需要向主机发送ACK信号, 主机就开始向我们发送数据了 523 /*****主机收到我们的RRQ后正确的回复应该是****/ 524 /*-----------------------------------------------------------------------* 525 * 6 | "timeout" | "5" | "blksize" | 1536 * 526 *-----------------------------------------------------------------------*/ 527 TftpState = STATE_OACK;//设置TFTP的状态 528 TftpRemotePort = src; 529 for (i = 0; i+8 < len; i++) { 530 if (strcmp((char *)pkt+i, "blksize") == 0) { 531 //把TftpBlkSize的大小设置为OACK包中的大小 532 TftpBlkSize = (unsigned short)simple_strtoul((char *)pkt+i+8, NULL, 10); 533 } 534 } 535 void TftpSend(); //tftp.c 此处分析的是TftpState处在STATE_OACK和STATE_DATA时的流程 536 uchar *pkt; 537 uchar *xp; 538 int len = 0; 539 ushort *s; 540 pkt = NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE; //pkt指向TFTP包 541 xp = pkt; 542 s = (ushort *)pkt; 543 s[0] = htons(TFTP_ACK); 544 s[1] = htons(TftpBlock); //0 此处的TftpBlock会在之后每次接收数据时, 接收到的内容Server自动增加了1 545 pkt = (uchar *)(s + 2); 546 len = pkt - xp; 547 NetSendUDPPacket(NetServerEther, TftpRemoteIP, TftpRemotePort, TftpOurPort, len); 548 //此函数在前面分析过 549 break; 550 case TFTP_DATA: 551 len -= 2; 552 TftpBlock = ntohs(*(__be16 *)pkt); 553 void update_block_number(); //tftp.c 554 if (((TftpBlock - 1) % 10) == 0) 555 putc('#'); 556 else if ((TftpBlock % (10 * HASHES_PER_LINE)) == 0) 557 puts("\n\t "); 558 //打印TFTP下载进度 559 if (TftpState == STATE_SEND_RRQ || TftpState == STATE_OACK || TftpState == STATE_RECV_WRQ) { 560 //第一次传送数据 561 TftpState = STATE_DATA; 562 TftpRemotePort = src; 563 void new_transfer(); //tftp.c 564 TftpLastBlock = 0; 565 TftpBlockWrap = 0; 566 TftpBlockWrapOffset = 0; 567 return; 568 if (TftpBlock != 1) { 569 //第一个TFTP数据包的TftpBlkSize不是1, 表示有错误 570 NetStartAgain(); //重启网卡 571 //if语句缩进补充 572 //if语句缩进补充 573 break; 574 } 575 } 576 if (TftpBlock == TftpLastBlock) { 577 //数据收发完成 578 //if语句缩进补充 579 break; 580 } 581 TftpLastBlock = TftpBlock; 582 TftpTimeoutCountMax = TIMEOUT_COUNT; 583 NetSetTimeout(TftpTimeoutMSecs, TftpTimeout); //更新timeout计时器 584 store_block(TftpBlock - 1, pkt + 2, len); //tftp.c 585 ulong offset = (TftpBlock - 1) * TftpBlkSize + TftpBlockWrapOffset; 586 ulong newsize = offset + len; 587 (void)memcpy((void *)(load_addr + offset), pkt + 2, len); 588 if (NetBootFileXferSize < newsize) 589 NetBootFileXferSize = newsize; 590 return; 591 TftpSend();//tftp.c 收到数据后给Server发送ACK 此处分析的是TftpState处在STATE_OACK和STATE_DATA时的流程 592 uchar *pkt; 593 uchar *xp; 594 int len = 0; 595 ushort *s; 596 pkt = NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE; //pkt指向TFTP包 597 xp = pkt; 598 s = (ushort *)pkt; 599 s[0] = htons(TFTP_ACK); 600 s[1] = htons(TftpBlock); //0 此处的TftpBlock会在之后每次接收数据时, 接收到的内容Server自动增加了1 601 pkt = (uchar *)(s + 2); 602 len = pkt - xp; 603 NetSendUDPPacket(NetServerEther, TftpRemoteIP, TftpRemotePort, TftpOurPort, len); 604 //此函数在前面分析过 605 if (len < TftpBlkSize) //发送的内容小于TftpBlkSize表示发送的是最后一个包, 发送完成 606 tftp_complete(); //tftp.c 607 time_start = get_timer(time_start); 608 if (time_start > 0) { 609 puts("\n\t "); 610 print_size(NetBootFileXferSize / time_start * 1000, "/s"); 611 } 612 puts("\ndone\n"); 613 net_set_state(NETLOOP_SUCCESS); 614 return; 615 //if缩进补全 616 break; 617 case TFTP_ERROR: 618 //TODO 省略错误信息 619 break; 620 } 621 return; 622 return; 623 break; 624 return; 625 //略去后面的代码 626 //前面写的是return int xxx(); 627 if (ctrlc()) { 628 //如果按下了ctrl+C 629 //TODO 分析按下ctrl+C的代码 630 } 631 void ArpTimeoutCheck(); //arp.c 632 //如果Arp等待超时, 重新发送, 如果超时次数达到一点限度, 重启网卡 633 return; 634 if (timeHandler && ((get_timer(0) - timeStart) > timeDelta)) { 635 //如果超时, 运行并置零timeHandler 636 //在TFTP超时后打印T, 当超时的次数到达TftpTimeoutCountMax时, 重启网卡 637 thand_f *x; 638 x = timeHandler; 639 timeHandler = (thand_f *)0; 640 (*x)(); 641 } 642 switch (net_state) { //net_state在net.c中 643 case NETLOOP_RESTART: 644 NetRestarted = 1; 645 goto start; 646 case NETLOOP_SUCCESS: 647 void net_cleanup_loop(); 648 //TODO 649 void eth_halt(); 650 //switch语句缩进补充 651 //for循环缩进补充 652 return NetBootFileXferSize; 653 case NETLOOP_FAIL: 654 net_cleanup_loop(); 655 //TODO 656 eth_set_last_protocol(BOOTP); 657 //TODO 658 //switch语句缩进补充 659 //for循环缩进补充 660 return NetBootFileXferSize; 661 case NETLOOP_CONTINUE: 662 continue; 663 } 664 //for循环缩进补充 665 void netboot_update_env(); //cmd_net.c 666 flush_cache(load_addr, size); 667 rcode = int bootm_maybe_autostart(cmdtp, argv[0]); //cmd_bootm.c 668 return 0; 669 return 0; 670 return 0; 671 //tftp命令执行完成