本篇是从0学ARM系列文章的最后一篇,后面暂无更新计划。
uboot中网络协议栈
网卡的驱动,对于上层协议来说,已经封装好了发送和接收数据的接口,那么上层协议栈只需要按照顺序调用对应的网卡驱动函数就可以进行网络数据的收发。
uboot中的协议栈相对来说比较简单,有以下几个特点:
传输层只支持UDP协议;目前只支持ICMP、TFTP、NFS、DNS、DHCP、CDP、SNTP等几种协议;网卡采用poll接收数据包,而不是中断方式;数据包的发送和接收操作是串行操作,不支持并发。
1. 网络协议栈架构
下面是uboot网络协议栈的函数调用流程:
2. 通过DNS命令来解析一个数据包的收发流程
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执行函数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 long");
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 setup", argv[1]);
420 return 1;
421 }
422
423 return 0;
424 }
406行 判断参数字符串长度,大于255非法411行 参数1必须是要解析的主机,存储在NetDNSResolve 中413~416行 保存dns命令的环境参数,该参数可以没有418行 进入网络协议处理函数入口NetLoop(),并将对应的协议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("Abort");
485 include a debug print as well incase the debug
486 messages are directed to stderr
487 debug_cond(DEBUG_INT_STATE, "--- NetLoop Abort!");
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)",
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!");
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!");
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 }