侵权投诉
订阅
纠错
加入自媒体

uboot中的协议栈有什么特点?

2021-05-25 13:47
一口Linux
关注

函数参数为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");

<上一页  1  2  
声明: 本文由入驻维科号的作者撰写,观点仅代表作者本人,不代表OFweek立场。如有侵权或其他问题,请联系举报。

发表评论

0条评论,0人参与

请输入评论内容...

请输入评论/评论长度6~500个字

您提交的评论过于频繁,请输入验证码继续

暂无评论

暂无评论

    电子工程 猎头职位 更多
    扫码关注公众号
    OFweek电子工程网
    获取更多精彩内容
    文章纠错
    x
    *文字标题:
    *纠错内容:
    联系邮箱:
    *验 证 码:

    粤公网安备 44030502002758号