- static int ip_rcv_finish(struct sk_buff*skb)
- {
- const struct iphdr
*iph = ip_hdr(skb);
- struct rtable *rt;
- /*
- * Initialise the virtual path cachefor 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;
- }