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命令执行完成
时间: 2024-10-09 02:08:59

U-boot的TFTP流程分析的相关文章

nova boot代码流程分析(三):nova与neutron的交互(2)

继续<nova boot代码流程分析(三):nova与neutron的交互(1)>的分析. #/nova/virt/libvirt/driver.py:LibvirtDriver # NOTE(ilyaalekseyev): Implementation like in multinics # for xenapi(tr3buchet) def spawn(self, context, instance, image_meta, injected_files, admin_password,

nova boot代码流程分析(五):VM启动从neutron-dhcp-agent获取IP与MAC

1.   network和subnet创建代码流程 [[email protected] ~(keystone_user1)]# neutron net-create demo-net [[email protected] ~(keystone_user1)]# neutron subnet-create  demo-net 1.1.1.0/24 --name demo-subnet --gateway 1.1.1.1 --enable_dhcp true 这里,我们主要分析上面两个命令的代码流

uboot boot流程分析

下面这篇文章分析得比较好: 2014.4新版uboot启动流程分析 http://blog.csdn.net/skyflying2012/article/details/25804209 感谢作者分享

U-boot引导流程分析一

U-Boot,全称 Universal Boot Loader,即通用引导程序,是遵循GPL条款的开放源码项目.它的源码目录.编译形式与Linux内核很相似,事实上,不少U-Boot源码就是相应的Linux内核源程序的简化,尤其是一些设备的驱动程序,这从U-Boot源码的注释中能体现这一点.U-Boot不仅仅支持嵌入式Linux系统的引导,它还支持NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS嵌入式操作系统. U-Boot的工作模式有启动加载模式和下载模式.

spring boot应用启动原理分析

spring boot quick start 在spring boot里,很吸引人的一个特性是可以直接把应用打包成为一个jar/war,然后这个jar/war是可以直接启动的,不需要另外配置一个Web Server. 如果之前没有使用过spring boot可以通过下面的demo来感受下. 下面以这个工程为例,演示如何启动Spring boot项目: git clone [email protected]:hengyunabc/spring-boot-demo.git mvn spring-b

Linux系统启动流程分析与关机流程

Linux 系统启动流程分析 Linux系统的启动过程并不是大家想象中的那么复杂,其过程可以分为5个阶段: 内核的引导. 运行 init. 系统初始化. 建立终端. 用户登录系统. init程序的类型: SysV: init, CentOS 5之前, 配置文件: /etc/inittab. Upstart: init,CentOS 6, 配置文件: /etc/inittab, /etc/init/*.conf. Systemd: systemd, CentOS 7,配置文件: /usr/lib/

Spring Boot实战与原理分析

1:Spring Boot概述与课程概要介绍 2:Spring4 快速入门 3:Spring4 扩展分析(一) 4:Spring4 扩展分析(二) 5:Spring Boot 快速入门 6:Spring Boot 配置分析(一) 7:Spring Boot 配置分析(二) 8:Spring Boot 自动配置 9:Spring Boot @Enable*注解的工作原理 10:Spring Boot @EnableAutoConfiguration深入分析 11:Spring Boot 事件监听

[国嵌笔记][030][U-Boot工作流程分析]

uboot工作流程分析 程序入口 1.打开顶层目录的Makefile,找到目标smdk2440_config的命令中的第三项(smdk2440) 2.进入目录board/samsung/smdk2440/,找到u-boot.lds文件.uboot的链接都是由这个链接器脚本来控制的 3.打开u-boot.lds文件,找到.text(代码段)的第一个文件cup/s3c24xx/start.o,该文件就是uboot的入口代码.链接器脚本中的ENTRY用来表明整个程序的入口,那么标号_start就是整个

u-boot启动流程分析(1)_平台相关部分

转自:http://www.wowotech.net/u-boot/boot_flow_1.html 1. 前言 本文将结合u-boot的“board—>machine—>arch—>cpu”框架,介绍u-boot中平台相关部分的启动流程.并通过对启动流程的简单分析,掌握u-boot移植的基本方法. 注1:本文所使用的u-boot版本,是2016/4/23从u-boot官网(git://git.denx.de/u-boot.git)导入的一个快照,具体可参考“https://github