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();
}