本篇是從0學ARM系列文章的最后一篇,后面暫無更新計劃。
想學習ARM知識,建議收藏下面的合集的鏈接。
《從0學ARM》
uboot中網絡協(xié)議棧
網卡的驅動,對于上層協(xié)議來說,已經封裝好了發(fā)送和接收數據的接口,那么上層協(xié)議棧只需要按照順序調用對應的網卡驅動函數就可以進行網絡數據的收發(fā)。
uboot中的協(xié)議棧相對來說比較簡單,有以下幾個特點:
- 傳輸層只支持UDP協(xié)議;目前只支持ICMP、TFTP、NFS、DNS、DHCP、CDP、SNTP等幾種協(xié)議;網卡采用poll接收數據包,而不是中斷方式;數據包的發(fā)送和接收操作是串行操作,不支持并發(fā)。
1. 網絡協(xié)議棧架構
下面是uboot網絡協(xié)議棧的函數調用流程:
2. 通過DNS命令來解析一個數據包的收發(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 );
當我們在uboot的命令終端輸入命令dns后,命令解析函數就會調用dns執(zhí)行函數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行 判斷參數字符串長度,大于255非法 411行 參數1必須是要解析的主機,存儲在NetDNSResolve 中 413~416行 保存dns命令的環(huán)境參數,該參數可以沒有 418行 進入網絡協(xié)議處理函數入口NetLoop(),并將對應的協(xié)議DNS傳遞給該函數
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 }
函數參數為DNS 352行 初始化網絡信息,讀取ipaddr、gatewayip、netmask、serverip、dnsip等環(huán)境變量的值并復制到對應的全局變量中
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行 對傳入的參數做switch操作,不同的協(xié)議進入到不同的處理流程 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行 函數net_set_udp_handler()主要將dns協(xié)議的回調函數DnsHandler()注冊到udp協(xié)議的回調指針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é)議回調函數指針
else
udp_packet_handler = f;
}
DnsStart()最終會調用函數DnsSend()發(fā)送dns協(xié)議數據包,該函數是根據dns協(xié)議填充udp數據包
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 != '