⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 icmp.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	Internet Control Message Protocol (ICMPv6) *	Linux INET6 implementation * *	Authors: *	Pedro Roque		<roque@di.fc.ul.pt> * *	$Id: icmp.c,v 1.37 2001/09/18 22:29:10 davem Exp $ * *	Based on net/ipv4/icmp.c * *	RFC 1885 * *	This program is free software; you can redistribute it and/or *      modify it under the terms of the GNU General Public License *      as published by the Free Software Foundation; either version *      2 of the License, or (at your option) any later version. *//* *	Changes: * *	Andi Kleen		:	exception handling *	Andi Kleen			add rate limits. never reply to a icmp. *					add more length checks and other fixes. *	yoshfuji		:	ensure to sent parameter problem for *					fragments. */#define __NO_VERSION__#include <linux/module.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/socket.h>#include <linux/in.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/sockios.h>#include <linux/net.h>#include <linux/skbuff.h>#include <linux/init.h>#include <linux/inet.h>#include <linux/netdevice.h>#include <linux/icmpv6.h>#include <net/ip.h>#include <net/sock.h>#include <net/ipv6.h>#include <net/checksum.h>#include <net/protocol.h>#include <net/raw.h>#include <net/rawv6.h>#include <net/transp_v6.h>#include <net/ip6_route.h>#include <net/addrconf.h>#include <net/icmp.h>#include <asm/uaccess.h>#include <asm/system.h>struct icmpv6_mib icmpv6_statistics[NR_CPUS*2];/* *	ICMP socket for flow control. */struct socket *icmpv6_socket;int icmpv6_rcv(struct sk_buff *skb);static struct inet6_protocol icmpv6_protocol = {	icmpv6_rcv,		/* handler		*/	NULL,			/* error control	*/	NULL,			/* next			*/	IPPROTO_ICMPV6,		/* protocol ID		*/	0,			/* copy			*/	NULL,			/* data			*/	"ICMPv6"	       	/* name			*/};struct icmpv6_msg {	struct icmp6hdr		icmph;	struct sk_buff		*skb;	int			offset;	struct in6_addr		*daddr;	int			len;	__u32			csum;};static int icmpv6_xmit_holder = -1;static int icmpv6_xmit_lock_bh(void){	if (!spin_trylock(&icmpv6_socket->sk->lock.slock)) {		if (icmpv6_xmit_holder == smp_processor_id())			return -EAGAIN;		spin_lock(&icmpv6_socket->sk->lock.slock);	}	icmpv6_xmit_holder = smp_processor_id();	return 0;}static __inline__ int icmpv6_xmit_lock(void){	int ret;	local_bh_disable();	ret = icmpv6_xmit_lock_bh();	if (ret)		local_bh_enable();	return ret;}static void icmpv6_xmit_unlock_bh(void){	icmpv6_xmit_holder = -1;	spin_unlock(&icmpv6_socket->sk->lock.slock);}static __inline__ void icmpv6_xmit_unlock(void){	icmpv6_xmit_unlock_bh();	local_bh_enable();}/* *	getfrag callback */static int icmpv6_getfrag(const void *data, struct in6_addr *saddr, 			   char *buff, unsigned int offset, unsigned int len){	struct icmpv6_msg *msg = (struct icmpv6_msg *) data;	struct icmp6hdr *icmph;	__u32 csum;	if (offset) {		csum = skb_copy_and_csum_bits(msg->skb, msg->offset +					      (offset - sizeof(struct icmp6hdr)),					      buff, len, msg->csum);		msg->csum = csum;		return 0;	}	csum = csum_partial_copy_nocheck((void *) &msg->icmph, buff,					 sizeof(struct icmp6hdr), msg->csum);	csum = skb_copy_and_csum_bits(msg->skb, msg->offset,				      buff + sizeof(struct icmp6hdr),				      len - sizeof(struct icmp6hdr), csum);	icmph = (struct icmp6hdr *) buff;	icmph->icmp6_cksum = csum_ipv6_magic(saddr, msg->daddr, msg->len,					     IPPROTO_ICMPV6, csum);	return 0; }/*  * Slightly more convenient version of icmpv6_send. */void icmpv6_param_prob(struct sk_buff *skb, int code, int pos){	icmpv6_send(skb, ICMPV6_PARAMPROB, code, pos, skb->dev);	kfree_skb(skb);}/* * Figure out, may we reply to this packet with icmp error. * * We do not reply, if: *	- it was icmp error message. *	- it is truncated, so that it is known, that protocol is ICMPV6 *	  (i.e. in the middle of some exthdr) * *	--ANK (980726) */static int is_ineligible(struct sk_buff *skb){	int ptr = (u8*)(skb->nh.ipv6h+1) - skb->data;	int len = skb->len - ptr;	__u8 nexthdr = skb->nh.ipv6h->nexthdr;	if (len < 0)		return 1;	ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, len);	if (ptr < 0)		return 0;	if (nexthdr == IPPROTO_ICMPV6) {		u8 type;		if (skb_copy_bits(skb, ptr+offsetof(struct icmp6hdr, icmp6_type),				  &type, 1)		    || !(type & 0x80))			return 1;	}	return 0;}int sysctl_icmpv6_time = 1*HZ; /*  * Check the ICMP output rate limit  */static inline int icmpv6_xrlim_allow(struct sock *sk, int type,				     struct flowi *fl){	struct dst_entry *dst;	int res = 0;	/* Informational messages are not limited. */	if (type & 0x80)		return 1;	/* Do not limit pmtu discovery, it would break it. */	if (type == ICMPV6_PKT_TOOBIG)		return 1;	/* 	 * Look up the output route.	 * XXX: perhaps the expire for routing entries cloned by	 * this lookup should be more aggressive (not longer than timeout).	 */	dst = ip6_route_output(sk, fl);	if (dst->error) {		IP6_INC_STATS(Ip6OutNoRoutes);	} else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) {		res = 1;	} else {		struct rt6_info *rt = (struct rt6_info *)dst;		int tmo = sysctl_icmpv6_time;		/* Give more bandwidth to wider prefixes. */		if (rt->rt6i_dst.plen < 128)			tmo >>= ((128 - rt->rt6i_dst.plen)>>5);		res = xrlim_allow(dst, tmo);	}	dst_release(dst);	return res;}/* *	an inline helper for the "simple" if statement below *	checks if parameter problem report is caused by an *	unrecognized IPv6 option that has the Option Type  *	highest-order two bits set to 10 */static __inline__ int opt_unrec(struct sk_buff *skb, __u32 offset){	u8 optval;	offset += skb->nh.raw - skb->data;	if (skb_copy_bits(skb, offset, &optval, 1))		return 1;	return (optval&0xC0) == 0x80;}/* *	Send an ICMP message in response to a packet in error */void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, 		 struct net_device *dev){	struct ipv6hdr *hdr = skb->nh.ipv6h;	struct sock *sk = icmpv6_socket->sk;	struct in6_addr *saddr = NULL;	int iif = 0;	struct icmpv6_msg msg;	struct flowi fl;	int addr_type = 0;	int len;	if ((u8*)hdr < skb->head || (u8*)(hdr+1) > skb->tail)		return;	/*	 *	Make sure we respect the rules 	 *	i.e. RFC 1885 2.4(e)	 *	Rule (e.1) is enforced by not using icmpv6_send	 *	in any code that processes icmp errors.	 */	addr_type = ipv6_addr_type(&hdr->daddr);	if (ipv6_chk_addr(&hdr->daddr, skb->dev))		saddr = &hdr->daddr;	/*	 *	Dest addr check	 */	if ((addr_type & IPV6_ADDR_MULTICAST || skb->pkt_type != PACKET_HOST)) {		if (type != ICMPV6_PKT_TOOBIG &&		    !(type == ICMPV6_PARAMPROB && 		      code == ICMPV6_UNK_OPTION && 		      (opt_unrec(skb, info))))			return;		saddr = NULL;	}	addr_type = ipv6_addr_type(&hdr->saddr);	/*	 *	Source addr check	 */	if (addr_type & IPV6_ADDR_LINKLOCAL)		iif = skb->dev->ifindex;	/*	 *	Must not send if we know that source is Anycast also.	 *	for now we don't know that.	 */	if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) {		if (net_ratelimit())			printk(KERN_DEBUG "icmpv6_send: addr_any/mcast source\n");		return;	}	/* 	 *	Never answer to a ICMP packet.	 */	if (is_ineligible(skb)) {		if (net_ratelimit())			printk(KERN_DEBUG "icmpv6_send: no reply to icmp error\n"); 		return;	}	fl.proto = IPPROTO_ICMPV6;	fl.nl_u.ip6_u.daddr = &hdr->saddr;	fl.nl_u.ip6_u.saddr = saddr;	fl.oif = iif;	fl.fl6_flowlabel = 0;	fl.uli_u.icmpt.type = type;	fl.uli_u.icmpt.code = code;	if (icmpv6_xmit_lock())		return;	if (!icmpv6_xrlim_allow(sk, type, &fl))		goto out;	/*	 *	ok. kick it. checksum will be provided by the 	 *	getfrag_t callback.	 */	msg.icmph.icmp6_type = type;	msg.icmph.icmp6_code = code;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -