uboot中的协议栈有什么特点?
函数参数为DNS352行 初始化网络信息,读取ipaddr、gatewayip、netmask、serverip、dnsip等环境变量的值并复制到对应的全局变量中
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操作,不同的协议进入到不同的处理流程428行 执行DnsStart(),
197 void
198 DnsStart(void)
199 {
200 debug("%s", __func__);
201
202 NetSetTimeout(DNS_TIMEOUT, DnsTimeout);
203 net_set_udp_handler(DnsHandler);
204
205 DnsSend();
206 }
203行 函数net_set_udp_handler()主要将dns协议的回调函数DnsHandler()注册到udp协议的回调指针udp_packet_handler,
void net_set_udp_handler(rxhand_f *f)
{
debug_cond(DEBUG_INT_STATE, "--- NetLoop UDP handler set (%p)", f);
if (f == NULL)
udp_packet_handler = dummy_handler;//注册到udp协议回调函数指针
else
udp_packet_handler = f;
}
DnsStart()最终会调用函数DnsSend()发送dns协议数据包,该函数是根据dns协议填充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 != '');
79
80 *p++ = 0; Mark end of host name
81 *p++ = 0; Some servers require double null
82 *p++ = (unsigned char) qtype; Query Type
83
84 *p++ = 0;
85 *p++ = 1; Class: inet, 0x0001
86
87 n = p - pkt; Total packet length
88 debug("Packet size %d", n);
89
90 DnsOurPort = random_port();
91
92 NetSendUDPPacket(NetServerEther, NetOurDNSIP, DNS_SERVICE_PORT,
93 DnsOurPort, n);
94 debug("DNS packet sent");
95 }
51~57行 根据dns协议填充dns协议头,数据帧首地址为NetTxPacket,此处通过指针pkt和p来填充dns数据帧60~85行 根据协议格式要求填充要解析的host名字到数据包87行 计算数据包长度90行 产生一个随机的端口号92~93行 调用udp协议的发送函数NetSendUDPPacket(),参数依次是:以太头信息,DNS服务器 ip地址,DNS服务器端口号,我们的dns服务端口号,数据包长度
688 int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport,
689 int payload_len)
690 {
691 uchar *pkt;
692 int eth_hdr_size;
693 int pkt_hdr_size;
694
695 make sure the NetTxPacket is initialized (NetInit() was called)
696 assert(NetTxPacket != NULL);
697 if (NetTxPacket == NULL)
698 return -1;
699
700 convert to new style broadcast
701 if (dest == 0)
702 dest = 0xFFFFFFFF;
703
704 if broadcast, make the ether address a broadcast and don't do ARP
705 if (dest == 0xFFFFFFFF)
706 ether = NetBcastAddr;
707
708 pkt = (uchar *)NetTxPacket;
709
710 eth_hdr_size = NetSetEther(pkt, ether, PROT_IP);
711 pkt += eth_hdr_size;
712 net_set_udp_header(pkt, dest, dport, sport, payload_len);
713 pkt_hdr_size = eth_hdr_size + IP_UDP_HDR_SIZE;
714
715 if MAC address was not discovered yet, do an ARP request
716 if (memcmp(ether, NetEtherNullAddr, 6) == 0) {
717 debug_cond(DEBUG_DEV_PKT, "sending ARP for %pI4", &dest);
718
719 save the ip and eth addr for the packet to send after arp
720 NetArpWaitPacketIP = dest;
721 NetArpWaitPacketMAC = ether;
722
723 size of the waiting packet
724 NetArpWaitTxPacketSize = pkt_hdr_size + payload_len;
725
726 and do the ARP request
727 NetArpWaitTry = 1;
728 NetArpWaitTimerStart = get_timer(0);
729 ArpRequest();
730 return 1; waiting
731 } else {
732 debug_cond(DEBUG_DEV_PKT, "sending UDP to %pI4/%pM",
733 &dest, ether);
734 NetSendPacket(NetTxPacket, pkt_hdr_size + payload_len);
735 return 0; transmitted
736 }
737 }
696~706行 参数检查710行 设置以太头713行 设置udp协议头716~730行 如果没有目的MAC地址,就要先发送ARP请求734行 调用函数NetSendPacket(),参数分别是:要发送数据帧的首地址,数据包长度
529 Transmit a packet
530 static inline void NetSendPacket(uchar *pkt, int len)
531 {
532 (void) eth_send(pkt, len);
533 }
532行 调用我们注册的函数dm9000_send()该函数已经分析过,根据流程图,回到函数NetLoop()
461~562行 循环接收网络数据包470行 调用网卡驱动接收函数eth_rx()
int eth_rx(void)
{
if (!eth_current)
return -1;
return eth_current->recv(eth_current);
}
eth_current->recv(eth_current)函数就是我们注册的网卡的接收函数dm9000_rx(),该函数我们上一章已经分析过,最终通过调用函数NetReceive(),将数据帧上传到协议栈
943 void
944 NetReceive(uchar *inpkt, int len)
945 {
946 struct ethernet_hdr *et;
947 struct ip_udp_hdr *ip;
948 IPaddr_t dst_ip;
949 IPaddr_t src_ip;
950 int eth_proto;
……
957
958 NetRxPacket = inpkt;
959 NetRxPacketLen = len;
960 et = (struct ethernet_hdr *)inpkt;
961
962 too small packet?
963 if (len < ETHER_HDR_SIZE)
964 return;
965
……
984
985 eth_proto = ntohs(et->et_protlen);
986
987 if (eth_proto < 1514) {
988 struct e802_hdr *et802 = (struct e802_hdr *)et;
……
997
998 } else if (eth_proto != PROT_VLAN) { normal packet
999 ip = (struct ip_udp_hdr *)(inpkt + ETHER_HDR_SIZE);
1000 len -= ETHER_HDR_SIZE;
1001
1002 } else { VLAN packet
……
1026 }
1027
……
1045 switch (eth_proto) {
……
1056 case PROT_IP:
1057 debug_cond(DEBUG_NET_PKT, "Got IP");
1058 Before we start poking the header, make sure it is there
1059 if (len < IP_UDP_HDR_SIZE) {
1060 debug("len bad %d < %lu", len,
1061 (ulong)IP_UDP_HDR_SIZE);
1062 return;
1063 }
1064 Check the packet length
1065 if (len < ntohs(ip->ip_len)) {
1066 debug("len bad %d < %d", len, ntohs(ip->ip_len));
1067 return;
1068 }
1069 len = ntohs(ip->ip_len);
1070 debug_cond(DEBUG_NET_PKT, "len=%d, v=%02x",
1071 len, ip->ip_hl_v & 0xff);
1072
1073 Can't deal with anything except IPv4
1074 if ((ip->ip_hl_v & 0xf0) != 0x40)
1075 return;
1076 Can't deal with IP options (headers != 20 bytes)
1077 if ((ip->ip_hl_v & 0x0f) > 0x05)
1078 return;
1079 Check the Checksum of the header
1080 if (!NetCksumOk((uchar *)ip, IP_HDR_SIZE / 2)) {
1081 debug("checksum bad");
1082 return;
1083 }
1084 If it is not for us, ignore it
1085 dst_ip = NetReadIP(&ip->ip_dst);
1092 Read source IP address for later use
1093 src_ip = NetReadIP(&ip->ip_src);
1184
1185 * IP header OK. Pass the packet to the current handler.
1186
1187 (*udp_packet_handler)((uchar *)ip + IP_UDP_HDR_SIZE,
1188 ntohs(ip->udp_dst),
1189 src_ip,
1190 ntohs(ip->udp_src),
1191 ntohs(ip->udp_len) - UDP_HDR_SIZE);
1192 break;
1193 }
1194 }
参数inpkt:指向接收到的以太数据包头 len:接收到的数据包的长度960行 变量NetRxPacket指向接收的数据头,以太数据包包头比定位以太协议头985行 从以太协议头提取出协议字段,该字段表示后面是否是ip协议999行 解析出ip协议头1045行 根据以太头协议进行switch操作1059~1083行 对协议头进行合法性检查1085行 读取出目的ip地址1093行 读取出源ip地址,1187行 ip协议头解析成功,调用udp协议回调函数udp_packet_handler(),该函数在之前的DnStart()注册了DnsHandler
104 static void
105 DnsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)
106 {
193
194 net_set_state(NETLOOP_SUCCESS);
195 }
该函数用于解析DNS协议,在此不再详解解析成功后194行,会设置当前执行状态为NETLOOP_SUCCESS,代码回到函数NetLoop()470行475行 判断是否按下ctrl+c快捷键,并作出操作522~562行 对执行结果进行处理,计入统计信息564行 如果net_state为NETLOOP_SUCCESS、NETLOOP_FAIL最终都会进入done,从而置空udp回调函数如果net_state为NETLOOP_CONTINUE,表明仍然有后续数据包要接收,则回到461行,继续下一个数据包的接收
至此DNS协议的处理流程分析完毕,大家可以根据这个流程自行分析其他几个协议的处理流程。
容易遇到的问题
有的时候能读取到 DM9000A 的 ID,连续操作就能读取到 DM9000A 的 ID,但间隔一会操作就读取不到 DM9000A 的 ID,通过调试,在 dm9000_reset 函数中加一句延时操作,就可以正常读取 DM9000A 的 ID 了。
277 do {
278 DM9000_DBG("resetting the DM9000, 2nd reset");
279 udelay(25); Wait at least 20 us
280 } while (DM9000_ior(DM9000_NCR) & 1);
281 udelay(150);
282 Check whether the ethernet controller is present
283 if ((DM9000_ior(DM9000_PIDL) != 0x0) ||
284 (DM9000_ior(DM9000_PIDH) != 0x90))
285 printf("ERROR: resetting DM9000 -> not responding");
图片新闻
技术文库
最新活动更多
-
即日-12.26立即报名>>> 【在线会议】村田用于AR/VR设计开发解决方案
-
1月8日火热报名中>> Allegro助力汽车电气化和底盘解决方案优化在线研讨会
-
1月9日立即预约>>> 【直播】ADI电能计量方案:新一代直流表、EV充电器和S级电能表
-
即日-1.14火热报名中>> OFweek2025中国智造CIO在线峰会
-
即日-1.16立即报名>>> 【在线会议】ImSym 开启全流程成像仿真时代
-
即日-1.20限时下载>>> 爱德克(IDEC)设备及工业现场安全解决方案
推荐专题
发表评论
请输入评论内容...
请输入评论/评论长度6~500个字
暂无评论
暂无评论