/* this routine now just gets the data out of the card and returns.
it's return values now mean.
1 <- exit even if you have more packets.
0 <- call me again no matter what.
-1 <- last packet not processed, try again. */
int
dev_rint(unsigned char *buff, unsigned long len, int flags,
struct device * dev)
{
struct sk_buff *skb=NULL;
struct packet_type *ptype;
unsigned short type;
unsigned char flag =0;
unsigned char *to;
int amount;
/* try to grab some memory. */
if (len > 0 && buff != NULL)
{
skb = malloc (sizeof (*skb) + len);
skb->mem_len = sizeof (*skb) + len;
skb->mem_addr = skb;
}
/* firs we copy the packet into a buffer, and save it for later. */
if (buff != NULL && skb != NULL)
{
if ( !(flags & IN_SKBUFF))
{
to = (unsigned char *)(skb+1);
while (len > 0)
{
amount = min (len, (unsigned long) dev->rmem_end -
(unsigned long) buff);
memcpy (to, buff, amount);
len -= amount;
buff += amount;
to += amount;
if ((unsigned long)buff == dev->rmem_end)
buff = (unsigned char *)dev->rmem_start;
}
}
else
{
free_s (skb->mem_addr, skb->mem_len);
skb = (struct sk_buff *)buff;
}
skb->len = len;
skb->dev = dev;
skb->sk = NULL;
/* now add it to the dev backlog. */
cli();
if (dev-> backlog == NULL)
{
skb->prev = skb;
skb->next = skb;
dev->backlog = skb;
}
else
{
skb ->prev = dev->backlog->prev;
skb->next = dev->backlog;
skb->next->prev = skb;
skb->prev->next = skb;
}
sti();
return (0);
}
if (skb != NULL)
free_s (skb->mem_addr, skb->mem_len);
/* anything left to process? */
if (dev->backlog == NULL)
{
if (buff == NULL)
{
sti();
return (1);
}
if (skb != NULL)
{
sti();
return (-1);
}
sti();
printk ("dev_rint:Dropping packets due to lack of memory\n");
return (1);
}
skb= dev->backlog;
if (skb->next == skb)
{
dev->backlog = NULL;
}
else
{
dev->backlog = skb->next;
skb->next->prev = skb->prev;
skb->prev->next = skb->next;
}
sti();
/* bump the pointer to the next structure. */
skb->h.raw = (unsigned char *)(skb+1) + dev->hard_header_len;
skb->len -= dev->hard_header_len;
// wd8003_init函数赋值eth_type_trans
// 获取链路层头enet_header的type字段。
/* convert the type to an ethernet type. */
type = dev->type_trans (skb, dev);
/* if there get to be a lot of types we should changes this to
a bunch of linked lists like we do for ip protocols. */
for (ptype = ptype_base; ptype != NULL; ptype=ptype->next)
{
if (ptype->type == type)
{
struct sk_buff *skb2;
/* copy the packet if we need to. */
if (ptype->copy)
{
skb2 = malloc (skb->mem_len);
if (skb2 == NULL) continue;
memcpy (skb2, skb, skb->mem_len);
skb2->mem_addr = skb2;
}
else
{
skb2 = skb;
flag = 1;
}
// ip_rcv 函数
ptype->func (skb2, dev, ptype);
}
}
if (!flag)
{
PRINTK ("discarding packet type = %X\n", type);
free_skb (skb, FREE_READ);
}
if (buff == NULL)
return (0);
else
return (-1);
}
int
ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
struct ip_header *iph;
unsigned char hash;
unsigned char flag=0;
static struct options opt; /* since we don't use these yet, and they
take up stack space. */
struct ip_protocol *ipprot;
iph=skb->h.iph;
PRINTK("<<\n");
print_iph(iph);
if (ip_csum (iph) || do_options (iph,&opt) || iph->version != 4)
{
PRINTK ("ip packet thrown out. \n");
skb->sk = NULL;
free_skb(skb, 0);
return (0);
}
/* for now we will only deal with packets meant for us. */
if (!my_ip_addr(iph->daddr))
{
PRINTK ("packet meant for someone else.\n");
skb->sk = NULL;
free_skb(skb, 0);
return (0);
}
/* deal with fragments. or don't for now.*/
if ((iph->frag_off & 64) || (net16(iph->frag_off)&0x1fff))
{
printk ("packet fragmented. \n");
skb->sk = NULL;
free_skb(skb, 0);
return(0);
}
skb->h.raw += iph->ihl*4;
/* add it to the arp table if it's talking to us. That way we
will be able to talk to them also. */
// IP首部的8位协议,根据协议进行分用。
hash = iph->protocol & (MAX_IP_PROTOS -1);
// ip_proto_init 函数中 调用add_ip_protocol 注册的
for (ipprot = ip_protos[hash]; ipprot != NULL; ipprot=ipprot->next)
{
struct sk_buff *skb2;
PRINTK ("Using protocol = %X:\n", ipprot);
print_ipprot (ipprot);
/* pass it off to everyone who wants it. */
/* we should check the return values here. */
/* see if we need to make a copy of it. This will
only be set if more than one protpocol wants it.
and then not for the last one. */
if (ipprot->copy)
{
skb2 = malloc (skb->mem_len);
if (skb2 == NULL) continue;
memcpy (skb2, skb, skb->mem_len);
skb2->mem_addr = skb2;
}
else
{
skb2 = skb;
}
flag = 1;
// 如果是tcp则tcp_rcv
ipprot->handler (skb2, dev, &opt, iph->daddr,
net16(iph->tot_len) - iph->ihl*4,
iph->saddr, 0, ipprot);
}
if (!flag)
{
icmp_reply (skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev);
skb->sk = NULL;
free_skb (skb, 0);
}
return (0);
}
int
tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len,
unsigned long saddr, int redo, struct ip_protocol * protocol)
{
struct tcp_header *th;
volatile struct sock *sk;
th = skb->h.th;
/* find the socket. */
sk=get_sock(&tcp_prot, net16(th->dest), saddr, th->source, daddr);
PRINTK("<<\n");
PRINTK("len = %d, redo = %d, skb=%X\n", len, redo, skb);
if (sk)
{
PRINTK ("sk = %X:\n",sk);
print_sk (sk);
}
if (!redo)
{
if (th->check && tcp_check (th, len, saddr, daddr ))
{
skb->sk = NULL;
free_skb (skb, 0);
/* we don't release the socket because it was never
marked in use. */
return (0);
}
/*See if we know about the socket. */
if (sk == NULL)
{
if (!th->rst)
tcp_reset (daddr, saddr, th, &tcp_prot, opt,dev);
skb->sk = NULL;
free_skb (skb, 0);
return (0);
}
skb->len = len;
skb->sk = sk;
skb->acked = 0;
skb->used = 0;
skb->free = 0;
skb->urg_used = 0;
skb->saddr = daddr;
skb->daddr = saddr;
th->seq = net32(th->seq);
cli();
/* we may need to add it to the backlog here. */
if (sk->inuse)
{
if (sk->back_log == NULL)
{
sk->back_log = skb;
skb->next = skb;
skb->prev = skb;
}
else
{
skb->next = sk->back_log;
skb->prev = sk->back_log->prev;
skb->prev->next = skb;
skb->next->prev = skb;
}
sti();
return (0);
}
sk->inuse = 1;
sti();
}
/* charge the memory to the socket. */
if (sk->rmem_alloc + skb->mem_len >= SK_RMEM_MAX)
{
skb->sk = NULL;
free_skb (skb, 0);
release_sock (sk);
return (0);
}
sk->rmem_alloc += skb->mem_len;
PRINTK ("About to do switch. \n");
/* now deal with it. */
switch (sk->state)
{
/* this should close the system down if it's waiting for an
ack that is never going to be sent. */
case TCP_LAST_ACK:
if (th->rst)
{
sk->err = ECONNRESET;
sk->state = TCP_CLOSE;
if (!sk->dead)
{
wake_up (sk->sleep);
}
free_skb (skb, FREE_READ);
release_sock(sk);
return (0);
}
case TCP_ESTABLISHED:
case TCP_FIN_WAIT1:
case TCP_FIN_WAIT2:
case TCP_TIME_WAIT:
if (!tcp_sequence (sk, th, len, opt, saddr))
{
free_skb (skb, FREE_READ);
release_sock(sk);
return (0);
}
if (th->rst)
{
sk->err = ECONNRESET;
sk->state = TCP_CLOSE;
if (!sk->dead)
{
wake_up (sk->sleep);
}
free_skb (skb, FREE_READ);
release_sock(sk);
return (0);
}
if (opt->security != 0 || opt->compartment != 0 || th->syn)
{
sk->err = ECONNRESET;
sk->state = TCP_CLOSE;
tcp_reset (daddr, saddr, th, sk->prot, opt,dev);
if (!sk->dead)
{
wake_up (sk->sleep);
}
free_skb (skb, FREE_READ);
release_sock(sk);
return (0);
}
if (th->ack)
{
if(!tcp_ack (sk, th, saddr))
{
free_skb (skb, FREE_READ);
release_sock(sk);
return (0);
}
}
if (th->urg)
{
if (tcp_urg (sk, th, saddr))
{
free_skb (skb, FREE_READ);
release_sock(sk);
return (0);
}
}
if ( tcp_data (skb, sk, saddr, len))
{
free_skb (skb, FREE_READ);
release_sock(sk);
return (0);
}
if (!th->fin)
{
release_sock(sk);
return (0);
}
tcp_fin (sk, th, saddr, dev);
release_sock(sk);
return (0);
case TCP_CLOSE:
if (sk->dead || sk->daddr)
{
PRINTK ("packet received for closed,dead socket\n");
free_skb (skb, FREE_READ);
release_sock (sk);
return (0);
}
if (!th->rst)
{
if (!th->ack)
th->ack_seq=0;
tcp_reset (daddr, saddr, th, sk->prot, opt,dev);
}
free_skb (skb, FREE_READ);
release_sock(sk);
return (0);
case TCP_LISTEN:
if (th->rst)
{
free_skb (skb, FREE_READ);
release_sock(sk);
return (0);
}
if (th->ack)
{
tcp_reset (daddr, saddr, th, sk->prot, opt,dev );
free_skb (skb, FREE_READ);
release_sock(sk);
return (0);
}
if (th->syn)
{
/* if (opt->security != 0 || opt->compartment != 0)
{
tcp_reset (daddr, saddr, th, prot, opt,dev);
release_sock(sk);
return (0);
} */
/* now we just put the whole thing including the header
and saddr, and protocol pointer into the buffer.
We can't respond until the user tells us to accept
the connection. */
tcp_conn_request (sk, skb, daddr, saddr, opt, dev);
release_sock(sk);
return (0);
}
free_skb (skb, FREE_READ);
release_sock(sk);
return (0);
default:
if (!tcp_sequence (sk, th, len, opt, saddr))
{
free_skb (skb, FREE_READ);
release_sock(sk);
return (0);
}
case TCP_SYN_SENT:
if (th->rst)
{
sk->err = ECONNREFUSED;
sk->state = TCP_CLOSE;
if (!sk->dead)
{
wake_up (sk->sleep);
}
free_skb (skb, FREE_READ);
release_sock(sk);
return (0);
}
/* if (opt->security != 0 || opt->compartment != 0 )
{
sk->err = ECONNRESET;
sk->state = TCP_CLOSE;
tcp_reset (daddr, saddr, th, sk->prot, opt, dev);
if (!sk->dead)
{
wake_up (sk->sleep);
}
free_skb (skb, FREE_READ);
release_sock(sk);
return (0);
} */
if (!th->ack)
{
if (th->syn)
{
sk->state = TCP_SYN_RECV;
}
free_skb (skb, FREE_READ);
release_sock(sk);
return (0);
}
switch (sk->state)
{
case TCP_SYN_SENT:
if (!tcp_ack(sk, th, saddr))
{
tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
free_skb (skb, FREE_READ);
release_sock(sk);
return (0);
}
/* if the syn bit is also set, switch to tcp_syn_recv,
and then to established. */
if (!th->syn)
{
free_skb (skb, FREE_READ);
release_sock (sk);
return (0);
}
/* ack the syn and fall through. */
sk->acked_seq = th->seq+1;
sk->fin_seq = th->seq;
tcp_send_ack (sk->send_seq, th->seq+1, sk,
th, sk->daddr);
case TCP_SYN_RECV:
if (!tcp_ack(sk, th, saddr))
{
tcp_reset(daddr, saddr, th, sk->prot, opt, dev);
free_skb (skb, FREE_READ);
release_sock(sk);
return (0);
}
sk->state = TCP_ESTABLISHED;
/* now we need to finish filling out some of the tcp
header. */
/* we need to check for mtu info. */
tcp_options(sk, th);
sk->dummy_th.dest = th->source;
sk->copied_seq = sk->acked_seq-1;
if (!sk->dead)
{
wake_up (sk->sleep);
}
/* now process the rest like we were already in the established
state. */
if (th->urg)
if (tcp_urg (sk, th, saddr))
{
free_skb (skb, FREE_READ);
release_sock(sk);
return (0);
}
if (tcp_data (skb, sk, saddr, len))
free_skb (skb, FREE_READ);
if (th->fin)
tcp_fin(sk, th, saddr, dev);
release_sock(sk);
return (0);
}
if (th->urg)
{
if (tcp_urg (sk, th, saddr))
{
free_skb (skb, FREE_READ);
release_sock (sk);
return (0);
}
}
if (tcp_data (skb, sk, saddr, len))
{
free_skb (skb, FREE_READ);
release_sock (sk);
return (0);
}
if (!th->fin)
{
release_sock(sk);
return (0);
}
tcp_fin (sk, th, saddr, dev);
release_sock(sk);
return (0);
}
}
概述
代码
main.c文件
start_kernel
函数会调用sock_init
函数初始化网络文件系统, 该函数又会调用注册的协议族函数表对应的初始化函数。AF_INET
对应的回调处理函数表是inet_proto_ops
中的ip_proto_init函数。 该函数除了注册传输层支持的协议,还初始化了支持的链路层,还有定时回调函数。dev_base在Space.c文件中定义,如下:
网络驱动初始化函数定义在we.c文件中,如下:
当网卡中断系统会调用注册的回调函数
wd8003_interrupt
。该回调函数根据从网卡寄存器读到的数据判断,如果是发送完一个包则调用wd_trs
->dev_tint
, 如果是接收到一个包则调用了wd_rcv
->dev_rint
。dev_rint
函数定义在dev.c文件中,如下:根据
eth_type_trans
函数解析的以太网报文头type
字段,如果是ETHERTYPE_IP
则调用ip_rcv
接收并处理包。 该函数定义在ip.c文件中,如下:总结
系统启动后,调用
start_kernel
<main.c文件中>,该函数又调用sock_init
<socket.c文件中>初始化网络文件系统, 该函数又调用了inet_proto_ops.ip_proto_init
<sock.c文件中>初始化inet协议族初始化函数, 该函数分别调用add_ip_protocol
(ip_protocol_base<protocols.c文件中>)<ip.c文件中> 注册传输层支持的协议到ip_protos
hash表中。 和dev_base.init
<Space.c文件> 注册链路层支持的协议, 其中loopback_init
是回环地址。 而wd8003_init
<we.c文件>则是网卡驱动,并调用irqaction (dev->irq, &wd8003_sigaction)
注册网卡中断回调函数wd8003_interrupt
。当有数据包到达时候,网卡给cpu发中断信号,该函数被调用执行。 最终调用到了ip_rcv
。