本篇是從0學(xué)ARM系列文章的最后一篇,后面暫無更新計(jì)劃。
想學(xué)習(xí)ARM知識(shí),建議收藏下面的合集的鏈接。
《從0學(xué)ARM》
uboot中網(wǎng)絡(luò)協(xié)議棧
網(wǎng)卡的驅(qū)動(dòng),對于上層協(xié)議來說,已經(jīng)封裝好了發(fā)送和接收數(shù)據(jù)的接口,那么上層協(xié)議棧只需要按照順序調(diào)用對應(yīng)的網(wǎng)卡驅(qū)動(dòng)函數(shù)就可以進(jìn)行網(wǎng)絡(luò)數(shù)據(jù)的收發(fā)。
uboot中的協(xié)議棧相對來說比較簡單,有以下幾個(gè)特點(diǎn):
- 傳輸層只支持UDP協(xié)議;目前只支持ICMP、TFTP、NFS、DNS、DHCP、CDP、SNTP等幾種協(xié)議;網(wǎng)卡采用poll接收數(shù)據(jù)包,而不是中斷方式;數(shù)據(jù)包的發(fā)送和接收操作是串行操作,不支持并發(fā)。
1. 網(wǎng)絡(luò)協(xié)議棧架構(gòu)
下面是uboot網(wǎng)絡(luò)協(xié)議棧的函數(shù)調(diào)用流程:
2. 通過DNS命令來解析一個(gè)數(shù)據(jù)包的收發(fā)流程
uboot中,所有的命令都用宏U_BOOT_CMD來定義, dns命令的定義如下:
426 U_BOOT_CMD(
427 dns, 3, 1, do_dns,
428 "lookup the IP of a hostname",
429 "hostname [envvar]"
430 );
當(dāng)我們在uboot的命令終端輸入命令dns后,命令解析函數(shù)就會(huì)調(diào)用dns執(zhí)行函數(shù)do_dns()
389 int do_dns(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
390 {
……
406 if (strlen(argv[1]) >= 255) {
407 printf("dns error: hostname too longn");
408 return 1;
409 }
410
411 NetDNSResolve = argv[1];
412
413 if (argc == 3)
414 NetDNSenvvar = argv[2];
415 else
416 NetDNSenvvar = NULL;
417
418 if (NetLoop(DNS) < 0) {
419 printf("dns lookup of %s failed, check setupn", argv[1]);
420 return 1;
421 }
422
423 return 0;
424 }
406行 判斷參數(shù)字符串長度,大于255非法 411行 參數(shù)1必須是要解析的主機(jī),存儲(chǔ)在NetDNSResolve 中 413~416行 保存dns命令的環(huán)境參數(shù),該參數(shù)可以沒有 418行 進(jìn)入網(wǎng)絡(luò)協(xié)議處理函數(shù)入口NetLoop(),并將對應(yīng)的協(xié)議DNS傳遞給該函數(shù)
NetLoop()代碼比較長,我們只分析其中比較重要的幾段代碼
316 /**********************************************************************/
317 /*
318 * Main network processing loop.
319 */
320
321 int NetLoop(enum proto_t protocol)
322 {
323 bd_t *bd = gd->bd;
324 int ret = -1;
…………
352 NetInitLoop();
…………
367 switch (protocol) {
368 case TFTPGET:
369 #ifdef CONFIG_CMD_TFTPPUT
370 case TFTPPUT:
371 #endif
372 /* always use ARP to get server ethernet address */
373 TftpStart(protocol);
374 break;
…………
426 #if defined(CONFIG_CMD_DNS)
427 case DNS:
428 DnsStart();
429 break;
430 #endif
438 }
…………
461 for (;;) {
462 WATCHDOG_RESET();
463 #ifdef CONFIG_SHOW_ACTIVITY
464 show_activity(1);
465 #endif
466 /*
467 * Check the ethernet for a new packet. The ethernet
468 * receive routine will process it.
469 */
470 eth_rx();
471
472 /*
473 * Abort if ctrl-c was pressed.
474 */
475 if (ctrlc()) {
476 /* cancel any ARP that may not have completed */
477 NetArpWaitPacketIP = 0;
478
479 net_cleanup_loop();
480 eth_halt();
481 /* Invalidate the last protocol */
482 eth_set_last_protocol(BOOTP);
483
484 puts("nAbortn");
485 /* include a debug print as well incase the debug
486 messages are directed to stderr */
487 debug_cond(DEBUG_INT_STATE, "--- NetLoop Abort!n");
488 goto done;
489 }
…………
522 switch (net_state) {
523
524 case NETLOOP_RESTART:
525 NetRestarted = 1;
526 goto restart;
527
528 case NETLOOP_SUCCESS:
529 net_cleanup_loop();
530 if (NetBootFileXferSize > 0) {
531 char buf[20];
532 printf("Bytes transferred = %ld (%lx hex)n",
533 NetBootFileXferSize,
534 NetBootFileXferSize);
535 sprintf(buf, "%lX", NetBootFileXferSize);
536 setenv("filesize", buf);
537
538 sprintf(buf, "%lX", (unsigned long)load_addr);
539 setenv("fileaddr", buf);
540 }
541 if (protocol != NETCONS)
542 eth_halt();
543 else
544 eth_halt_state_only();
545
546 eth_set_last_protocol(protocol);
547
548 ret = NetBootFileXferSize;
549 debug_cond(DEBUG_INT_STATE, "--- NetLoop Success!n");
550 goto done;
551
552 case NETLOOP_FAIL:
553 net_cleanup_loop();
554 /* Invalidate the last protocol */
555 eth_set_last_protocol(BOOTP);
556 debug_cond(DEBUG_INT_STATE, "--- NetLoop Fail!n");
557 goto done;
558
559 case NETLOOP_CONTINUE:
560 continue;
561 }
562 }
563
564 done:
565 #ifdef CONFIG_CMD_TFTPPUT
566 /* Clear out the handlers */
567 net_set_udp_handler(NULL);
568 net_set_icmp_handler(NULL);
569 #endif
570 return ret;
571 }
函數(shù)參數(shù)為DNS 352行 初始化網(wǎng)絡(luò)信息,讀取ipaddr、gatewayip、netmask、serverip、dnsip等環(huán)境變量的值并復(fù)制到對應(yīng)的全局變量中
static void NetInitLoop(void)
{
static int env_changed_id;
int env_id = get_env_id();
/* update only when the environment has changed */
if (env_changed_id != env_id) {
NetOurIP = getenv_IPaddr("ipaddr");
NetOurGatewayIP = getenv_IPaddr("gatewayip");
NetOurSubnetMask = getenv_IPaddr("netmask");
NetServerIP = getenv_IPaddr("serverip");
NetOurNativeVLAN = getenv_VLAN("nvlan");
NetOurVLAN = getenv_VLAN("vlan");
#if defined(CONFIG_CMD_DNS)
NetOurDNSIP = getenv_IPaddr("dnsip");
#endif
env_changed_id = env_id;
}
memcpy(NetOurEther, eth_get_dev()->enetaddr, 6);
return;
}
367行 對傳入的參數(shù)做switch操作,不同的協(xié)議進(jìn)入到不同的處理流程 428行 執(zhí)行DnsStart(),
197 void
198 DnsStart(void)
199 {
200 debug("%sn", __func__);
201
202 NetSetTimeout(DNS_TIMEOUT, DnsTimeout);
203 net_set_udp_handler(DnsHandler);
204
205 DnsSend();
206 }
203行 函數(shù)net_set_udp_handler()主要將dns協(xié)議的回調(diào)函數(shù)DnsHandler()注冊到udp協(xié)議的回調(diào)指針udp_packet_handler,
void net_set_udp_handler(rxhand_f *f)
{
debug_cond(DEBUG_INT_STATE, "--- NetLoop UDP handler set (%p)n", f);
if (f == NULL)
udp_packet_handler = dummy_handler;//注冊到udp協(xié)議回調(diào)函數(shù)指針
else
udp_packet_handler = f;
}
DnsStart()最終會(huì)調(diào)用函數(shù)DnsSend()發(fā)送dns協(xié)議數(shù)據(jù)包,該函數(shù)是根據(jù)dns協(xié)議填充udp數(shù)據(jù)包
37 static void
38 DnsSend(void)
39 {
40 struct header *header;
41 int n, name_len;
42 uchar *p, *pkt;
43 const char *s;
44 const char *name;
45 enum dns_query_type qtype = DNS_A_RECORD;
46
47 name = NetDNSResolve;
48 pkt = p = (uchar *)(NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE);
49
50 /* Prepare DNS packet header */
51 header = (struct header *) pkt;
52 header->tid = 1;
53 header->flags = htons(0x100); /* standard query */
54 header->nqueries = htons(1); /* Just one query */
55 header->nanswers = 0;
56 header->nauth = 0;
57 header->nother = 0;
58
59 /* Encode DNS name */
60 name_len = strlen(name);
61 p = (uchar *) &header->data; /* For encoding host name into packet */
62
63 do {
64 s = strchr(name, '.');
65 if (!s)
66 s = name + name_len;
67
68 n = s - name; /* Chunk length */
69 *p++ = n; /* Copy length */
70 memcpy(p, name, n); /* Copy chunk */
71 p += n;
72
73 if (*s == '.')
74 n++;
75
76 name += n;
77 name_len -= n;
78 } while (*s != '