您的位置:首页 > 理论基础 > 计算机网络

linux 1.2.13 网络解析--收报分析(二层至三层过程)

2013-07-01 15:55 393 查看
linux 内核版本 1.2.13

文件:net/inet/dev.c 

1.
/*

 * Receive a packet from a device driver and queue it for the upper

 * (protocol) levels.  It always succeeds. This is the recommended 

 * interface to use.

 */

void netif_rx(struct sk_buff *skb)  //skb在上一步工作中,已经部分初始化
{
static int dropping = 0;
/*
*Any received buffers are un-owned and should be discarded
*when freed. These will be updated later as the frames get
*owners.
*/
skb->sk = NULL;
skb->free = 1;
if(skb->stamp.tv_sec==0)
skb->stamp = xtime;
/*
*Check that we aren't overdoing things.
*/
if (!backlog_size)
  dropping = 0;
else if (backlog_size > 300)
dropping = 1;
if (dropping) 
{
kfree_skb(skb, FREE_READ);
return;
}
/*
*Add it to the "backlog" queue. 
*/
#ifdef CONFIG_SKB_CHECK
IS_SKB(skb);
#endif
skb_queue_tail(&backlog,skb);//加入接收对列
backlog_size++;
/*
*If any packet arrived, mark it for processing after the
*hardware interrupt returns.
*/
mark_bh(NET_BH);
return;
}

//中断上半部完成
/*

 * When we are called the queue is ready to grab, the interrupts are

 * on and hardware can interrupt and queue to the receive queue a we

 * run with no problems.

 * This is run as a bottom half after an interrupt handler that does

 * mark_bh(NET_BH);

 */

 

void net_bh(void *tmp)

{
struct sk_buff *skb;
struct packet_type *ptype;
struct packet_type *pt_prev;
unsigned short type;
/*
* Atomically check and mark our BUSY state. 
*/

if (set_bit(1, (void*)&in_bh))
return;
/*
* Can we send anything now? We want to clear the
* decks for any more sends that get done as we
* process the input.
*/

dev_transmit();

 
/*
* Any data left to process. This may occur because a
* mark_bh() is done after we empty the queue including
* that from the device which does a mark_bh() just after
*/

cli();

/*
* While the queue is not empty
*/ 
while((skb=skb_dequeue(&backlog))!=NULL)  //抽取队列数据
{
/*
*We have a packet. Therefore the queue has shrunk
*/
  backlog_size--;
sti();
      /*
*Bump the pointer to the next structure.
*This assumes that the basic 'skb' pointer points to
*the MAC header, if any (as indicated by its "length"
*field).  Take care now!
*/
skb->h.raw = skb->data + skb->dev->hard_header_len;
skb->len -= skb->dev->hard_header_len;
      /*
*Fetch the packet protocol ID.  This is also quite ugly, as
*it depends on the protocol driver (the interface itself) to
*know what the type is, or where to get it from.  The Ethernet
*interfaces fetch the ID from the two bytes in the Ethernet MAC
*header (the h_proto field in struct ethhdr), but other drivers
*may either use the ethernet ID's or extra ones that do not
*clash (eg ETH_P_AX25). We could set this before we queue the
*frame. In fact I may change this when I have time.
*/
type = skb->dev->type_trans(skb, skb->dev);//获得二层协议类型
/*
*We got a packet ID.  Now loop over the "known protocols"
*table (which is actually a linked list, but this will
*change soon if I get my way- FvK), and forward the packet
*to anyone who wants it.
*
*[FvK didn't get his way but he is right this ought to be
*hashed so we typically get a single hit. The speed cost
*here is minimal but no doubt adds up at the 4,000+ pkts/second
*rate we can hit flat out]
*/
pt_prev = NULL;
for (ptype = ptype_base; ptype != NULL; ptype = ptype->next) 
{
if ((ptype->type == type || ptype->type == htons(ETH_P_ALL)) && (!ptype->dev || ptype->dev==skb->dev))
{
/*
*We already have a match queued. Deliver
*to it and then remember the new match
*/
if(pt_prev)
{
struct sk_buff *skb2;
skb2=skb_clone(skb, GFP_ATOMIC);
/*
*Kick the protocol handler. This should be fast
*and efficient code.
*/
if(skb2)
pt_prev->func(skb2, skb->dev, pt_prev);  //根据type类型,找到三层入口并执行 如:ip_packet_type.ip_rcv
}
/* Remember the current last to do */
pt_prev=ptype;
}
} /* End of protocol list loop */
/*
*Is there a last item to send to ?
*/
if(pt_prev)
pt_prev->func(skb, skb->dev, pt_prev);//根据type类型,找到三层入口并执行 如:ip_packet_type.ip_rcv
/*
*Has an unknown packet has been received ?
*/ 
else
kfree_skb(skb, FREE_WRITE);
/*
*Again, see if we can transmit anything now. 
*[Ought to take this out judging by tests it slows
*us down not speeds us up]
*/
dev_transmit();
cli();
  }/* End of queue loop */
  /*
  *We have emptied the queue
  */
  in_bh = 0;
sti();
/*
*One last output flush.
*/
 
dev_transmit();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: