全部博文(436)
分类: LINUX
2010-10-29 20:53:17
/* Deal with incoming ICMP packets.处理传入的ICMP数据包 接收icmp包*/
int
icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
unsigned long daddr, unsigned short len,
unsigned long saddr, int redo, struct inet_protocol *protocol)
{
struct icmphdr *icmph;
unsigned char *buff;
/* Drop broadcast packets. 丢弃掉广播包/
if (chk_addr(daddr) == IS_BROADCAST) {//如果目的地是本地I广播包
DPRINTF((DBG_ICMP, "ICMP: Discarded broadcast from %s\n",
in_ntoa(saddr)));//分辨是否为自己IP地址
skb1->sk = NULL;
kfree_skb(skb1, FREE_READ);
return(0);//如果不是,将该包释放
}
buff = skb1->h.raw;
icmph = (struct icmphdr *) buff;
/* Validate the packet first */首先验证包的合法性.
if (ip_compute_csum((unsigned char *) icmph, len)) {
/* Failed checksum! */校验和失败!
printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));//校验和不等于源主机的校验和
skb1->sk = NULL;
kfree_skb(skb1, FREE_READ);//释放该包
return(0);
}
print_icmp(icmph);
/* Parse the ICMP message */解析ICMP消息
switch(icmph->type) {
case ICMP_TIME_EXCEEDED: //超时
case ICMP_DEST_UNREACH://不可达
case ICMP_SOURCE_QUENCH://源抑制
icmp_unreach(icmph, skb1);
return(0);
case ICMP_REDIRECT://重定向
icmp_redirect(icmph, skb1, dev);
return(0);
case ICMP_ECHO: //ECHO请求
icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt);
return 0;
case ICMP_ECHOREPLY://EHCO应答
skb1->sk = NULL;
kfree_skb(skb1, FREE_READ);
return(0);
case ICMP_INFO_REQUEST://信息请求
icmp_info(icmph, skb1, dev, saddr, daddr, len, opt);
return 0;
case ICMP_INFO_REPLY://信息应答
skb1->sk = NULL;
kfree_skb(skb1, FREE_READ);
return(0);
case ICMP_ADDRESS: //地址掩码请求
icmp_address(icmph, skb1, dev, saddr, daddr, len, opt);
return 0;
case ICMP_ADDRESSREPLY://地址掩码应答
skb1->sk = NULL;
kfree_skb(skb1, FREE_READ);
return(0);
default:
DPRINTF((DBG_ICMP,
"ICMP: Unsupported ICMP from %s, type = 0x%X\n",
in_ntoa(saddr), icmph->type));
skb1->sk = NULL;
kfree_skb(skb1, FREE_READ);
return(0);
}
/*NOTREACHED*/
skb1->sk = NULL;
kfree_skb(skb1, FREE_READ);
return(-1);
}
/* Perform any ICMP-related I/O control requests. */执行任何ICMP的相关的I / O控制请求
int
icmp_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
switch(cmd) {判断CMD
case DDIOCSDBG: 如果cmd确定是DDIOCSDBG 这个I/O口
return(dbg_ioctl((void *) arg, DBG_ICMP)); 则返回DBG_IP
default:
return(-EINVAL);否则返回错误
}
return(0);
ioctl对设备进行了判断,对I/O设备进行管理
}
功能:处理来到的ICMP数据包。
1.增加ICMP统计的入报文记数
2.如果入参len小于ICMP头结构大小,增加ICMP统计的接收错误报文记数,调用NETDEBUG,指明报文不完整,以FREE-READ为参释放skb空间,返回0
3.如果计算校验和失败,增加ICMP统计的接收错误报文记数,调用NETDEBUG,指明校验和出错,以FREE-READ为参释放skb空间,返回0
4.如果类型大于18,增加ICMP统计的接收错误报文记数,以FREE-READ为参释放skb空间,返回0
5.若定义了透明代理,条件为入参目标地址不等于设备协议地址但是广播或多播地址;
否则,条件为入参目标地址不等于设备协议地址且不是本机地址:
A.若类型不是ECHO,增加接收(IN)错误统计记数,以FREE-READ为参释放skb空间,返回0(slientl ignore)
B.否则,将入参目标地址置为设备协议地址。
6.增加对应icmp_pointers表项的input计数,调用它的处理器函数,返回0