- static int ip_rcv_finish(struct sk_buff *skb)
- {
- const struct iphdr *iph = ip_hdr(skb);
- struct rtable *rt;
- /*
- * Initialise the virtual path cache for the packet. It describes
- * how the packet travels inside Linux networking.
- */
- /*
- * 通常从外界接收的数据包,skb->dst不会包含路由信息,暂时还不知道在何处会设置
- * 这个字段。ip_route_input函数会根据路由表设置路由信息,暂时不考虑路由系统。
- */
- if (skb->dst == NULL) {
- int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
- skb->dev);
- if (unlikely(err)) {
- if (err == -EHOSTUNREACH)
- IP_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
- else if (err == -ENETUNREACH)
- IP_INC_STATS_BH(IPSTATS_MIB_INNOROUTES);
- goto drop;
- }
- }
- /* 更新流量控制所需要的统计数据,忽略 */
- #ifdef CONFIG_NET_CLS_ROUTE
- if (unlikely(skb->dst->tclassid)) {
- struct ip_rt_acct *st = ip_rt_acct + 256*smp_processor_id();
- u32 idx = skb->dst->tclassid;
- st[idx&0xFF].o_packets++;
- st[idx&0xFF].o_bytes+=skb->len;
- st[(idx>>16)&0xFF].i_packets++;
- st[(idx>>16)&0xFF].i_bytes+=skb->len;
- }
- #endif
- /* 如果IP头部大于20字节,则表示IP头部包含IP选项,需要进行选项处理.暂时忽略,毕竟很少用 */
- if (iph->ihl > 5 && ip_rcv_options(skb))
- goto drop;
- /* skb->dst包含路由信息。根据路由类型更新SNMP统计数据 */
- rt = (struct rtable*)skb->dst;
- if (rt->rt_type == RTN_MULTICAST)
- IP_INC_STATS_BH(IPSTATS_MIB_INMCASTPKTS);
- else if (rt->rt_type == RTN_BROADCAST)
- IP_INC_STATS_BH(IPSTATS_MIB_INBCASTPKTS);
- /*
- * dst_input实际上会调用skb->dst->input(skb).input函数会根据路由信息设置为合适的
- * 函数指针,如果是递交到本地的则为ip_local_deliver,若是转发则为ip_forward.
- * 暂时仅先考虑ip_local_deliver。
- */
- return dst_input(skb);
- drop:
- kfree_skb(skb);
- return NET_RX_DROP;
- }
linux TCP/IP协议栈 ---ip_rcv_finish()
订阅:
博文评论 (Atom)
没有评论:
发表评论