【lwip】09-IPv4协议&超全源码实现分析( 八 )

9.6 IP层数据流图

【lwip】09-IPv4协议&超全源码实现分析

文章插图
9.7 IP层输出ipv4 。
当上层需要发送数据时,会先将自己的数据包组装在一个pbuf中 。并将payload指针指向对应协议首部 。
然后调用ip_output()发送数据,需要给ip_output()函数提供源IP、目的IP、协议类型、TTL等重要信息让其组IP包 。
该函数直接或者间接调用ip4_route_src()根据目的IP选出一个匹配的网卡作为本次IP数据包传输网卡 。
选出后调用ip4_output_if()进行IP数据包组包,并调用netif->output()发送出去 。或者调用netif_loop_output()环回到本网卡 。
9.7.1 发送数据报上层调用ip_output()把数据转交给IP层处理,lwip支持ipv4和ipv6,这里默认分析ipv4,因为ipv6也是一大块,后面有时间再完整分析下 。
/** * @ingroup ip * Output IP packet, netif is selected by source address */#define ip_output(p, src, dest, ttl, tos, proto) \(IP_IS_V6(dest) ? \ip6_output(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto) : \ip4_output(p, ip_2_ip4(src), ip_2_ip4(dest), ttl, tos, proto))9.7.2 ip层前期处理:ip4_output()ipv4发包:
  • 检查pbuf的引用ref是否为1 。为1才能说明当前pbuf没有被其它地方引用,因为IP层处理可能会改变这个pbuf的部分指针值,如payload 。
  • 调用ip4_route_src()匹配网卡 。
  • 调用ip4_output_if()把数据包传入IP层处理 。
/** * Simple interface to ip_output_if. It finds the outgoing network * interface and calls upon ip_output_if to do the actual work. * * @param p the packet to send (p->payload points to the data, e.g. nextprotocol header; if dest == LWIP_IP_HDRINCL, p already includes anIP header and p->payload points to that IP header) * @param src the source IP address to send from (if src =https://www.huyubaike.com/biancheng/= IP4_ADDR_ANY, the *IPaddress of the netif used to send is used as source address) * @param dest the destination IP address to send the packet to * @param ttl the TTL value to be set in the IP header * @param tos the TOS value to be set in the IP header * @param proto the PROTOCOL to be set in the IP header * * @return ERR_RTE if no route is found *see ip_output_if() for more return values */err_tip4_output(struct pbuf *p, const ip4_addr_t *src, const ip4_addr_t *dest,u8_t ttl, u8_t tos, u8_t proto){struct netif *netif;/* 下传到IP层的pbuf的ref必须为1,即是没有被其它地方引用,因为pbuf下传到IP层后,pbuf的payload指针会被更改 。如果这个pbuf被其它地方引用了,可能会导致数据混乱 。*/LWIP_IP_CHECK_PBUF_REF_COUNT_FOR_TX(p);/* 根据目的IP地址为数据报寻找一个合适的网络接口(匹配网卡) */if ((netif = ip4_route_src(src, dest)) == NULL) { /* 没找到,记录信息,返回错误 */LWIP_DEBUGF(IP_DEBUG, ("ip4_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest)));IP_STATS_INC(ip.rterr);return ERR_RTE;}/* 匹配到网卡,传入IP层处理:组包、发送 */return ip4_output_if(p, src, dest, ttl, tos, proto, netif);}9.7.3 发包前的网卡匹配IP层收到上层的数据包后,需要匹配到网络接口,才能组IP包发出去 。
这里调用ip4_route_src()进行网卡匹配 。具体分析参考前面 。
9.7.4 组建、发送IP包注意几个函数的区别: