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

📄 raw.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * INET		An implementation of the TCP/IP protocol suite for the LINUX *		operating system.  INET is implemented using the  BSD Socket *		interface as the means of communication with the user level. * *		RAW - implementation of IP "raw" sockets. * * Version:	$Id: raw.c,v 1.63 2001/07/10 04:29:01 davem Exp $ * * Authors:	Ross Biro, <bir7@leland.Stanford.Edu> *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> * * Fixes: *		Alan Cox	:	verify_area() fixed up *		Alan Cox	:	ICMP error handling *		Alan Cox	:	EMSGSIZE if you send too big a packet *		Alan Cox	: 	Now uses generic datagrams and shared *					skbuff library. No more peek crashes, *					no more backlogs *		Alan Cox	:	Checks sk->broadcast. *		Alan Cox	:	Uses skb_free_datagram/skb_copy_datagram *		Alan Cox	:	Raw passes ip options too *		Alan Cox	:	Setsocketopt added *		Alan Cox	:	Fixed error return for broadcasts *		Alan Cox	:	Removed wake_up calls *		Alan Cox	:	Use ttl/tos *		Alan Cox	:	Cleaned up old debugging *		Alan Cox	:	Use new kernel side addresses *	Arnt Gulbrandsen	:	Fixed MSG_DONTROUTE in raw sockets. *		Alan Cox	:	BSD style RAW socket demultiplexing. *		Alan Cox	:	Beginnings of mrouted support. *		Alan Cox	:	Added IP_HDRINCL option. *		Alan Cox	:	Skip broadcast check if BSDism set. *		David S. Miller	:	New socket lookup architecture. * *		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. */ #include <linux/config.h> #include <asm/system.h>#include <asm/uaccess.h>#include <asm/ioctls.h>#include <linux/types.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/timer.h>#include <linux/mm.h>#include <linux/kernel.h>#include <linux/fcntl.h>#include <linux/socket.h>#include <linux/in.h>#include <linux/inet.h>#include <linux/netdevice.h>#include <linux/mroute.h>#include <net/ip.h>#include <net/protocol.h>#include <linux/skbuff.h>#include <net/sock.h>#include <net/icmp.h>#include <net/udp.h>#include <net/raw.h>#include <net/inet_common.h>#include <net/checksum.h>struct sock *raw_v4_htable[RAWV4_HTABLE_SIZE];rwlock_t raw_v4_lock = RW_LOCK_UNLOCKED;static void raw_v4_hash(struct sock *sk){	struct sock **skp = &raw_v4_htable[sk->num & (RAWV4_HTABLE_SIZE - 1)];	write_lock_bh(&raw_v4_lock);	if ((sk->next = *skp) != NULL)		(*skp)->pprev = &sk->next;	*skp = sk;	sk->pprev = skp;	sock_prot_inc_use(sk->prot); 	sock_hold(sk);	write_unlock_bh(&raw_v4_lock);}static void raw_v4_unhash(struct sock *sk){ 	write_lock_bh(&raw_v4_lock);	if (sk->pprev) {		if (sk->next)			sk->next->pprev = sk->pprev;		*sk->pprev = sk->next;		sk->pprev = NULL;		sock_prot_dec_use(sk->prot);		__sock_put(sk);	}	write_unlock_bh(&raw_v4_lock);}struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num,			     unsigned long raddr, unsigned long laddr,			     int dif){	struct sock *s = sk;	for (s = sk; s; s = s->next) {		if (s->num == num 				&&		    !(s->daddr && s->daddr != raddr) 		&&		    !(s->rcv_saddr && s->rcv_saddr != laddr)	&&		    !(s->bound_dev_if && s->bound_dev_if != dif))			break; /* gotcha */	}	return s;}/* *	0 - deliver *	1 - block */static __inline__ int icmp_filter(struct sock *sk, struct sk_buff *skb){	int type;	type = skb->h.icmph->type;	if (type < 32) {		__u32 data = sk->tp_pinfo.tp_raw4.filter.data;		return ((1 << type) & data) != 0;	}	/* Do not block unknown ICMP types */	return 0;}/* IP input processing comes here for RAW socket delivery. * This is fun as to avoid copies we want to make no surplus * copies. * * RFC 1122: SHOULD pass TOS value up to the transport layer. * -> It does. And not only TOS, but all IP header. */struct sock *raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash){	struct sock *sk;	read_lock(&raw_v4_lock);	if ((sk = raw_v4_htable[hash]) == NULL)		goto out;	sk = __raw_v4_lookup(sk, iph->protocol,			     iph->saddr, iph->daddr,			     skb->dev->ifindex);	while (sk) {		struct sock *sknext = __raw_v4_lookup(sk->next, iph->protocol,						      iph->saddr, iph->daddr,						      skb->dev->ifindex);		if (iph->protocol != IPPROTO_ICMP ||		    !icmp_filter(sk, skb)) {			struct sk_buff *clone;			if (!sknext)				break;			clone = skb_clone(skb, GFP_ATOMIC);			/* Not releasing hash table! */			if (clone)				raw_rcv(sk, clone);		}		sk = sknext;	}out:	if (sk)		sock_hold(sk);	read_unlock(&raw_v4_lock);	return sk;}void raw_err (struct sock *sk, struct sk_buff *skb, u32 info){	int type = skb->h.icmph->type;	int code = skb->h.icmph->code;	int err = 0;	int harderr = 0;	/* Report error on raw socket, if:	   1. User requested ip_recverr.	   2. Socket is connected (otherwise the error indication	      is useless without ip_recverr and error is hard.	 */	if (!sk->protinfo.af_inet.recverr && sk->state != TCP_ESTABLISHED)		return;	switch (type) {	default:	case ICMP_TIME_EXCEEDED:		err = EHOSTUNREACH;		break;	case ICMP_SOURCE_QUENCH:		return;	case ICMP_PARAMETERPROB:		err = EPROTO;		harderr = 1;		break;	case ICMP_DEST_UNREACH:		err = EHOSTUNREACH;		if (code > NR_ICMP_UNREACH)			break;		err = icmp_err_convert[code].errno;		harderr = icmp_err_convert[code].fatal;		if (code == ICMP_FRAG_NEEDED) {			harderr = sk->protinfo.af_inet.pmtudisc !=					IP_PMTUDISC_DONT;			err = EMSGSIZE;		}	}	if (sk->protinfo.af_inet.recverr) {		struct iphdr *iph = (struct iphdr*)skb->data;		u8 *payload = skb->data + (iph->ihl << 2);		if (sk->protinfo.af_inet.hdrincl)			payload = skb->data;		ip_icmp_error(sk, skb, err, 0, info, payload);	}	if (sk->protinfo.af_inet.recverr || harderr) {		sk->err = err;		sk->error_report(sk);	}}static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb){	/* Charge it to the socket. */		if (sock_queue_rcv_skb(sk, skb) < 0) {		IP_INC_STATS(IpInDiscards);		kfree_skb(skb);		return NET_RX_DROP;	}	IP_INC_STATS(IpInDelivers);	return NET_RX_SUCCESS;}int raw_rcv(struct sock *sk, struct sk_buff *skb){	skb_push(skb, skb->data - skb->nh.raw);	raw_rcv_skb(sk, skb);	return 0;}struct rawfakehdr {	struct	iovec *iov;	u32	saddr;	struct	dst_entry *dst;};/* *	Send a RAW IP packet. *//* *	Callback support is trivial for SOCK_RAW */  static int raw_getfrag(const void *p, char *to, unsigned int offset,			unsigned int fraglen){	struct rawfakehdr *rfh = (struct rawfakehdr *) p;	return memcpy_fromiovecend(to, rfh->iov, offset, fraglen);}/* *	IPPROTO_RAW needs extra work. */ static int raw_getrawfrag(const void *p, char *to, unsigned int offset,				unsigned int fraglen){	struct rawfakehdr *rfh = (struct rawfakehdr *) p;	if (memcpy_fromiovecend(to, rfh->iov, offset, fraglen))		return -EFAULT;	if (!offset) {		struct iphdr *iph = (struct iphdr *)to;		if (!iph->saddr)			iph->saddr = rfh->saddr;		iph->check   = 0;		iph->tot_len = htons(fraglen); /* This is right as you can't						  frag RAW packets */		/*	 	 *	Deliberate breach of modularity to keep 	 	 *	ip_build_xmit clean (well less messy).		 */		if (!iph->id)			ip_select_ident(iph, rfh->dst, NULL);		iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);	}	return 0;}static int raw_sendmsg(struct sock *sk, struct msghdr *msg, int len){	struct ipcm_cookie ipc;	struct rawfakehdr rfh;	struct rtable *rt = NULL;	int free = 0;	u32 daddr;	u8  tos;	int err;	/* This check is ONLY to check for arithmetic overflow	   on integer(!) len. Not more! Real check will be made	   in ip_build_xmit --ANK	   BTW socket.c -> af_*.c -> ... make multiple	   invalid conversions size_t -> int. We MUST repair it f.e.	   by replacing all of them with size_t and revise all	   the places sort of len += sizeof(struct iphdr)	   If len was ULONG_MAX-10 it would be cathastrophe  --ANK	 */	err = -EMSGSIZE;	if (len < 0 || len > 0xFFFF)		goto out;	/*	 *	Check the flags.	 */	err = -EOPNOTSUPP;	if (msg->msg_flags & MSG_OOB)	/* Mirror BSD error message */		goto out;               /* compatibility */			 	/*	 *	Get and verify the address. 	 */	if (msg->msg_namelen) {		struct sockaddr_in *usin = (struct sockaddr_in*)msg->msg_name;		err = -EINVAL;		if (msg->msg_namelen < sizeof(*usin))			goto out;		if (usin->sin_family != AF_INET) {			static int complained;			if (!complained++)				printk(KERN_INFO "%s forgot to set AF_INET in "

⌨️ 快捷键说明

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