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

📄 raw.c

📁 《嵌入式系统设计与实例开发实验教材二源码》Linux内核移植与编译实验
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	RAW sockets for IPv6 *	Linux INET6 implementation  * *	Authors: *	Pedro Roque		<roque@di.fc.ul.pt>	 * *	Adapted from linux/net/ipv4/raw.c * *	$Id: raw.c,v 1.50 2001/09/18 22:29:10 davem Exp $ * *	Fixes: *	Hideaki YOSHIFUJI	:	sin6_scope_id support * *	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/errno.h>#include <linux/types.h>#include <linux/socket.h>#include <linux/sockios.h>#include <linux/sched.h>#include <linux/net.h>#include <linux/in6.h>#include <linux/netdevice.h>#include <linux/if_arp.h>#include <linux/icmpv6.h>#include <asm/uaccess.h>#include <asm/ioctls.h>#include <net/sock.h>#include <net/snmp.h>#include <net/ipv6.h>#include <net/ndisc.h>#include <net/protocol.h>#include <net/ip6_route.h>#include <net/addrconf.h>#include <net/transp_v6.h>#include <net/udp.h>#include <net/inet_common.h>#include <net/rawv6.h>struct sock *raw_v6_htable[RAWV6_HTABLE_SIZE];rwlock_t raw_v6_lock = RW_LOCK_UNLOCKED;static void raw_v6_hash(struct sock *sk){	struct sock **skp = &raw_v6_htable[sk->num & (RAWV6_HTABLE_SIZE - 1)];	write_lock_bh(&raw_v6_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_v6_lock);}static void raw_v6_unhash(struct sock *sk){ 	write_lock_bh(&raw_v6_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_v6_lock);}/* Grumble... icmp and ip_input want to get at this... */struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num,			     struct in6_addr *loc_addr, struct in6_addr *rmt_addr){	struct sock *s = sk;	int addr_type = ipv6_addr_type(loc_addr);	for(s = sk; s; s = s->next) {		if(s->num == num) {			struct ipv6_pinfo *np = &s->net_pinfo.af_inet6;			if (!ipv6_addr_any(&np->daddr) &&			    ipv6_addr_cmp(&np->daddr, rmt_addr))				continue;			if (!ipv6_addr_any(&np->rcv_saddr)) {				if (ipv6_addr_cmp(&np->rcv_saddr, loc_addr) == 0)					break;				if ((addr_type & IPV6_ADDR_MULTICAST) &&				    inet6_mc_check(s, loc_addr))					break;				continue;			}			break;		}	}	return s;}/* *	0 - deliver *	1 - block */static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb){	struct icmp6hdr *icmph;	struct raw6_opt *opt;	opt = &sk->tp_pinfo.tp_raw;	if (pskb_may_pull(skb, sizeof(struct icmp6hdr))) {		__u32 *data = &opt->filter.data[0];		int bit_nr;		icmph = (struct icmp6hdr *) skb->data;		bit_nr = icmph->icmp6_type;		return (data[bit_nr >> 5] & (1 << (bit_nr & 31))) != 0;	}	return 0;}/* *	demultiplex raw sockets. *	(should consider queueing the skb in the sock receive_queue *	without calling rawv6.c) */struct sock * ipv6_raw_deliver(struct sk_buff *skb, int nexthdr){	struct in6_addr *saddr;	struct in6_addr *daddr;	struct sock *sk, *sk2;	__u8 hash;	saddr = &skb->nh.ipv6h->saddr;	daddr = saddr + 1;	hash = nexthdr & (MAX_INET_PROTOS - 1);	read_lock(&raw_v6_lock);	sk = raw_v6_htable[hash];	/*	 *	The first socket found will be delivered after	 *	delivery to transport protocols.	 */	if (sk == NULL)		goto out;	sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr);	if (sk) {		sk2 = sk;		while ((sk2 = __raw_v6_lookup(sk2->next, nexthdr, daddr, saddr))) {			struct sk_buff *buff;			if (nexthdr == IPPROTO_ICMPV6 &&			    icmpv6_filter(sk2, skb))				continue;			buff = skb_clone(skb, GFP_ATOMIC);			if (buff)				rawv6_rcv(sk2, buff);		}	}	if (sk && nexthdr == IPPROTO_ICMPV6 && icmpv6_filter(sk, skb))		sk = NULL;out:	if (sk)		sock_hold(sk);	read_unlock(&raw_v6_lock);	return sk;}/* This cleans up af_inet6 a bit. -DaveM */static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len){	struct sockaddr_in6 *addr = (struct sockaddr_in6 *) uaddr;	__u32 v4addr = 0;	int addr_type;	int err;	if (addr_len < SIN6_LEN_RFC2133)		return -EINVAL;	addr_type = ipv6_addr_type(&addr->sin6_addr);	/* Raw sockets are IPv6 only */	if (addr_type == IPV6_ADDR_MAPPED)		return(-EADDRNOTAVAIL);	lock_sock(sk);	err = -EINVAL;	if (sk->state != TCP_CLOSE)		goto out;	if (addr_type & IPV6_ADDR_LINKLOCAL) {		if (addr_len >= sizeof(struct sockaddr_in6) &&		    addr->sin6_scope_id) {			/* Override any existing binding, if another one			 * is supplied by user.			 */			sk->bound_dev_if = addr->sin6_scope_id;		}		/* Binding to link-local address requires an interface */		if (sk->bound_dev_if == 0)			goto out;	}	/* Check if the address belongs to the host. */	if (addr_type != IPV6_ADDR_ANY) {		/* ipv4 addr of the socket is invalid.  Only the		 * unpecified and mapped address have a v4 equivalent.		 */		v4addr = LOOPBACK4_IPV6;		if (!(addr_type & IPV6_ADDR_MULTICAST))	{			err = -EADDRNOTAVAIL;			if (!ipv6_chk_addr(&addr->sin6_addr, NULL))				goto out;		}	}	sk->rcv_saddr = v4addr;	sk->saddr = v4addr;	ipv6_addr_copy(&sk->net_pinfo.af_inet6.rcv_saddr, &addr->sin6_addr);	if (!(addr_type & IPV6_ADDR_MULTICAST))		ipv6_addr_copy(&sk->net_pinfo.af_inet6.saddr, &addr->sin6_addr);	err = 0;out:	release_sock(sk);	return err;}void rawv6_err(struct sock *sk, struct sk_buff *skb,	       struct inet6_skb_parm *opt,	       int type, int code, int offset, u32 info){	int err;	int harderr;	/* Report error on raw socket, if:	   1. User requested recverr.	   2. Socket is connected (otherwise the error indication	      is useless without recverr and error is hard.	 */	if (!sk->net_pinfo.af_inet6.recverr && sk->state != TCP_ESTABLISHED)		return;	harderr = icmpv6_err_convert(type, code, &err);	if (type == ICMPV6_PKT_TOOBIG)		harderr = (sk->net_pinfo.af_inet6.pmtudisc == IPV6_PMTUDISC_DO);	if (sk->net_pinfo.af_inet6.recverr) {		u8 *payload = skb->data;		if (!sk->protinfo.af_inet.hdrincl)			payload += offset;		ipv6_icmp_error(sk, skb, err, 0, ntohl(info), payload);	}	if (sk->net_pinfo.af_inet6.recverr || harderr) {		sk->err = err;		sk->error_report(sk);	}}static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb){	/* Charge it to the socket. */	if (sock_queue_rcv_skb(sk,skb)<0) {		IP6_INC_STATS_BH(Ip6InDiscards);		kfree_skb(skb);		return 0;	}	IP6_INC_STATS_BH(Ip6InDelivers);	return 0;}/* *	This is next to useless...  *	if we demultiplex in network layer we don't need the extra call *	just to queue the skb...  *	maybe we could have the network decide uppon a hint if it  *	should call raw_rcv for demultiplexing */int rawv6_rcv(struct sock *sk, struct sk_buff *skb){	if (sk->protinfo.af_inet.hdrincl) {		__skb_push(skb, skb->nh.raw - skb->data);		skb->h.raw = skb->nh.raw;	}	rawv6_rcv_skb(sk, skb);	return 0;}/* *	This should be easy, if there is something there *	we return it, otherwise we block. */int rawv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,		  int noblock, int flags, int *addr_len){	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)msg->msg_name;	struct sk_buff *skb;	int copied, err;	if (flags & MSG_OOB)		return -EOPNOTSUPP;			if (addr_len) 		*addr_len=sizeof(*sin6);	if (flags & MSG_ERRQUEUE)		return ipv6_recv_error(sk, msg, len);	skb = skb_recv_datagram(sk, flags, noblock, &err);	if (!skb)		goto out;	copied = skb->len;  	if (copied > len) {  		copied = len;  		msg->msg_flags |= MSG_TRUNC;  	}	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);	if (err)		goto out_free;	/* Copy the address. */	if (sin6) {		sin6->sin6_family = AF_INET6;		memcpy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr, 		       sizeof(struct in6_addr));		sin6->sin6_flowinfo = 0;		sin6->sin6_scope_id = 0;		if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) {			struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb;			sin6->sin6_scope_id = opt->iif;		}	}	sock_recv_timestamp(msg, sk, skb);	if (sk->net_pinfo.af_inet6.rxopt.all)		datagram_recv_ctl(sk, msg, skb);	err = copied;out_free:	skb_free_datagram(sk, skb);out:	return err;}/* *	Sending... */struct rawv6_fakehdr {	struct iovec	*iov;	struct sock	*sk;	__u32		len;	__u32		cksum;	__u32		proto;	struct in6_addr *daddr;};static int rawv6_getfrag(const void *data, struct in6_addr *saddr, 			  char *buff, unsigned int offset, unsigned int len){	struct iovec *iov = (struct iovec *) data;	return memcpy_fromiovecend(buff, iov, offset, len);}static int rawv6_frag_cksum(const void *data, struct in6_addr *addr,			     char *buff, unsigned int offset, 			     unsigned int len){	struct rawv6_fakehdr *hdr = (struct rawv6_fakehdr *) data;		if (csum_partial_copy_fromiovecend(buff, hdr->iov, offset, 						    len, &hdr->cksum))		return -EFAULT;		if (offset == 0) {		struct sock *sk;		struct raw6_opt *opt;		struct in6_addr *daddr;				sk = hdr->sk;		opt = &sk->tp_pinfo.tp_raw;		if (hdr->daddr)			daddr = hdr->daddr;		else			daddr = addr + 1;				hdr->cksum = csum_ipv6_magic(addr, daddr, hdr->len,					     hdr->proto, hdr->cksum);				if (opt->offset < len) {			__u16 *csum;

⌨️ 快捷键说明

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