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

📄 ipv6_sockglue.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
			retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);		break;	}	case IPV6_JOIN_ANYCAST:	case IPV6_LEAVE_ANYCAST:	{		struct ipv6_mreq mreq;		if (optlen != sizeof(struct ipv6_mreq))			goto e_inval;		retv = -EFAULT;		if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq)))			break;		if (optname == IPV6_JOIN_ANYCAST)			retv = ipv6_sock_ac_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);		else			retv = ipv6_sock_ac_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);		break;	}	case MCAST_JOIN_GROUP:	case MCAST_LEAVE_GROUP:	{		struct group_req greq;		struct sockaddr_in6 *psin6;		retv = -EFAULT;		if (copy_from_user(&greq, optval, sizeof(struct group_req)))			break;		if (greq.gr_group.ss_family != AF_INET6) {			retv = -EADDRNOTAVAIL;			break;		}		psin6 = (struct sockaddr_in6 *)&greq.gr_group;		if (optname == MCAST_JOIN_GROUP)			retv = ipv6_sock_mc_join(sk, greq.gr_interface,				&psin6->sin6_addr);		else			retv = ipv6_sock_mc_drop(sk, greq.gr_interface,				&psin6->sin6_addr);		break;	}	case MCAST_JOIN_SOURCE_GROUP:	case MCAST_LEAVE_SOURCE_GROUP:	case MCAST_BLOCK_SOURCE:	case MCAST_UNBLOCK_SOURCE:	{		struct group_source_req greqs;		int omode, add;		if (optlen != sizeof(struct group_source_req))			goto e_inval;		if (copy_from_user(&greqs, optval, sizeof(greqs))) {			retv = -EFAULT;			break;		}		if (greqs.gsr_group.ss_family != AF_INET6 ||		    greqs.gsr_source.ss_family != AF_INET6) {			retv = -EADDRNOTAVAIL;			break;		}		if (optname == MCAST_BLOCK_SOURCE) {			omode = MCAST_EXCLUDE;			add = 1;		} else if (optname == MCAST_UNBLOCK_SOURCE) {			omode = MCAST_EXCLUDE;			add = 0;		} else if (optname == MCAST_JOIN_SOURCE_GROUP) {			struct sockaddr_in6 *psin6;			psin6 = (struct sockaddr_in6 *)&greqs.gsr_group;			retv = ipv6_sock_mc_join(sk, greqs.gsr_interface,				&psin6->sin6_addr);			/* prior join w/ different source is ok */			if (retv && retv != -EADDRINUSE)				break;			omode = MCAST_INCLUDE;			add = 1;		} else /* MCAST_LEAVE_SOURCE_GROUP */ {			omode = MCAST_INCLUDE;			add = 0;		}		retv = ip6_mc_source(add, omode, sk, &greqs);		break;	}	case MCAST_MSFILTER:	{		extern int sysctl_mld_max_msf;		struct group_filter *gsf;		if (optlen < GROUP_FILTER_SIZE(0))			goto e_inval;		if (optlen > sysctl_optmem_max) {			retv = -ENOBUFS;			break;		}		gsf = kmalloc(optlen,GFP_KERNEL);		if (!gsf) {			retv = -ENOBUFS;			break;		}		retv = -EFAULT;		if (copy_from_user(gsf, optval, optlen)) {			kfree(gsf);			break;		}		/* numsrc >= (4G-140)/128 overflow in 32 bits */		if (gsf->gf_numsrc >= 0x1ffffffU ||		    gsf->gf_numsrc > sysctl_mld_max_msf) {			kfree(gsf);			retv = -ENOBUFS;			break;		}		if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) {			kfree(gsf);			retv = -EINVAL;			break;		}		retv = ip6_mc_msfilter(sk, gsf);		kfree(gsf);		break;	}	case IPV6_ROUTER_ALERT:		retv = ip6_ra_control(sk, val, NULL);		break;	case IPV6_MTU_DISCOVER:		if (val<0 || val>3)			goto e_inval;		np->pmtudisc = val;		retv = 0;		break;	case IPV6_MTU:		if (val && val < IPV6_MIN_MTU)			goto e_inval;		np->frag_size = val;		retv = 0;		break;	case IPV6_RECVERR:		np->recverr = valbool;		if (!val)			skb_queue_purge(&sk->sk_error_queue);		retv = 0;		break;	case IPV6_FLOWINFO_SEND:		np->sndflow = valbool;		retv = 0;		break;	case IPV6_FLOWLABEL_MGR:		retv = ipv6_flowlabel_opt(sk, optval, optlen);		break;	case IPV6_IPSEC_POLICY:	case IPV6_XFRM_POLICY:		retv = -EPERM;		if (!capable(CAP_NET_ADMIN))			break;		retv = xfrm_user_policy(sk, optname, optval, optlen);		break;	}	release_sock(sk);	return retv;e_inval:	release_sock(sk);	return -EINVAL;}int ipv6_setsockopt(struct sock *sk, int level, int optname,		    char __user *optval, int optlen){	int err;	if (level == SOL_IP && sk->sk_type != SOCK_RAW)		return udp_prot.setsockopt(sk, level, optname, optval, optlen);	if (level != SOL_IPV6)		return -ENOPROTOOPT;	err = do_ipv6_setsockopt(sk, level, optname, optval, optlen);#ifdef CONFIG_NETFILTER	/* we need to exclude all possible ENOPROTOOPTs except default case */	if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&			optname != IPV6_XFRM_POLICY) {		lock_sock(sk);		err = nf_setsockopt(sk, PF_INET6, optname, optval,				optlen);		release_sock(sk);	}#endif	return err;}EXPORT_SYMBOL(ipv6_setsockopt);#ifdef CONFIG_COMPATint compat_ipv6_setsockopt(struct sock *sk, int level, int optname,			   char __user *optval, int optlen){	int err;	if (level == SOL_IP && sk->sk_type != SOCK_RAW) {		if (udp_prot.compat_setsockopt != NULL)			return udp_prot.compat_setsockopt(sk, level, optname,							  optval, optlen);		return udp_prot.setsockopt(sk, level, optname, optval, optlen);	}	if (level != SOL_IPV6)		return -ENOPROTOOPT;	err = do_ipv6_setsockopt(sk, level, optname, optval, optlen);#ifdef CONFIG_NETFILTER	/* we need to exclude all possible ENOPROTOOPTs except default case */	if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&	    optname != IPV6_XFRM_POLICY) {		lock_sock(sk);		err = compat_nf_setsockopt(sk, PF_INET6, optname,					   optval, optlen);		release_sock(sk);	}#endif	return err;}EXPORT_SYMBOL(compat_ipv6_setsockopt);#endifstatic int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt,				  int optname, char __user *optval, int len){	struct ipv6_opt_hdr *hdr;	if (!opt)		return 0;	switch(optname) {	case IPV6_HOPOPTS:		hdr = opt->hopopt;		break;	case IPV6_RTHDRDSTOPTS:		hdr = opt->dst0opt;		break;	case IPV6_RTHDR:		hdr = (struct ipv6_opt_hdr *)opt->srcrt;		break;	case IPV6_DSTOPTS:		hdr = opt->dst1opt;		break;	default:		return -EINVAL;	/* should not happen */	}	if (!hdr)		return 0;	len = min_t(unsigned int, len, ipv6_optlen(hdr));	if (copy_to_user(optval, hdr, len))		return -EFAULT;	return ipv6_optlen(hdr);}static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,		    char __user *optval, int __user *optlen){	struct ipv6_pinfo *np = inet6_sk(sk);	int len;	int val;	if (get_user(len, optlen))		return -EFAULT;	switch (optname) {	case IPV6_ADDRFORM:		if (sk->sk_protocol != IPPROTO_UDP &&		    sk->sk_protocol != IPPROTO_UDPLITE &&		    sk->sk_protocol != IPPROTO_TCP)			return -EINVAL;		if (sk->sk_state != TCP_ESTABLISHED)			return -ENOTCONN;		val = sk->sk_family;		break;	case MCAST_MSFILTER:	{		struct group_filter gsf;		int err;		if (len < GROUP_FILTER_SIZE(0))			return -EINVAL;		if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0)))			return -EFAULT;		lock_sock(sk);		err = ip6_mc_msfget(sk, &gsf,			(struct group_filter __user *)optval, optlen);		release_sock(sk);		return err;	}	case IPV6_2292PKTOPTIONS:	{		struct msghdr msg;		struct sk_buff *skb;		if (sk->sk_type != SOCK_STREAM)			return -ENOPROTOOPT;		msg.msg_control = optval;		msg.msg_controllen = len;		msg.msg_flags = 0;		lock_sock(sk);		skb = np->pktoptions;		if (skb)			atomic_inc(&skb->users);		release_sock(sk);		if (skb) {			int err = datagram_recv_ctl(sk, &msg, skb);			kfree_skb(skb);			if (err)				return err;		} else {			if (np->rxopt.bits.rxinfo) {				struct in6_pktinfo src_info;				src_info.ipi6_ifindex = np->mcast_oif;				ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr);				put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);			}			if (np->rxopt.bits.rxhlim) {				int hlim = np->mcast_hops;				put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);			}			if (np->rxopt.bits.rxoinfo) {				struct in6_pktinfo src_info;				src_info.ipi6_ifindex = np->mcast_oif;				ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr);				put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info);			}			if (np->rxopt.bits.rxohlim) {				int hlim = np->mcast_hops;				put_cmsg(&msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim);			}		}		len -= msg.msg_controllen;		return put_user(len, optlen);	}	case IPV6_MTU:	{		struct dst_entry *dst;		val = 0;		lock_sock(sk);		dst = sk_dst_get(sk);		if (dst) {			val = dst_mtu(dst);			dst_release(dst);		}		release_sock(sk);		if (!val)			return -ENOTCONN;		break;	}	case IPV6_V6ONLY:		val = np->ipv6only;		break;	case IPV6_RECVPKTINFO:		val = np->rxopt.bits.rxinfo;		break;	case IPV6_2292PKTINFO:		val = np->rxopt.bits.rxoinfo;		break;	case IPV6_RECVHOPLIMIT:		val = np->rxopt.bits.rxhlim;		break;	case IPV6_2292HOPLIMIT:		val = np->rxopt.bits.rxohlim;		break;	case IPV6_RECVRTHDR:		val = np->rxopt.bits.srcrt;		break;	case IPV6_2292RTHDR:		val = np->rxopt.bits.osrcrt;		break;	case IPV6_HOPOPTS:	case IPV6_RTHDRDSTOPTS:	case IPV6_RTHDR:	case IPV6_DSTOPTS:	{		lock_sock(sk);		len = ipv6_getsockopt_sticky(sk, np->opt,					     optname, optval, len);		release_sock(sk);		return put_user(len, optlen);	}	case IPV6_RECVHOPOPTS:		val = np->rxopt.bits.hopopts;		break;	case IPV6_2292HOPOPTS:		val = np->rxopt.bits.ohopopts;		break;	case IPV6_RECVDSTOPTS:		val = np->rxopt.bits.dstopts;		break;	case IPV6_2292DSTOPTS:		val = np->rxopt.bits.odstopts;		break;	case IPV6_TCLASS:		val = np->tclass;		if (val < 0)			val = 0;		break;	case IPV6_RECVTCLASS:		val = np->rxopt.bits.rxtclass;		break;	case IPV6_FLOWINFO:		val = np->rxopt.bits.rxflow;		break;	case IPV6_UNICAST_HOPS:	case IPV6_MULTICAST_HOPS:	{		struct dst_entry *dst;		if (optname == IPV6_UNICAST_HOPS)			val = np->hop_limit;		else			val = np->mcast_hops;		dst = sk_dst_get(sk);		if (dst) {			if (val < 0)				val = dst_metric(dst, RTAX_HOPLIMIT);			if (val < 0)				val = ipv6_get_hoplimit(dst->dev);			dst_release(dst);		}		if (val < 0)			val = ipv6_devconf.hop_limit;		break;	}	case IPV6_MULTICAST_LOOP:		val = np->mc_loop;		break;	case IPV6_MULTICAST_IF:		val = np->mcast_oif;		break;	case IPV6_MTU_DISCOVER:		val = np->pmtudisc;		break;	case IPV6_RECVERR:		val = np->recverr;		break;	case IPV6_FLOWINFO_SEND:		val = np->sndflow;		break;	default:		return -ENOPROTOOPT;	}	len = min_t(unsigned int, sizeof(int), len);	if(put_user(len, optlen))		return -EFAULT;	if(copy_to_user(optval,&val,len))		return -EFAULT;	return 0;}int ipv6_getsockopt(struct sock *sk, int level, int optname,		    char __user *optval, int __user *optlen){	int err;	if (level == SOL_IP && sk->sk_type != SOCK_RAW)		return udp_prot.getsockopt(sk, level, optname, optval, optlen);	if(level != SOL_IPV6)		return -ENOPROTOOPT;	err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);#ifdef CONFIG_NETFILTER	/* we need to exclude all possible ENOPROTOOPTs except default case */	if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {		int len;		if (get_user(len, optlen))			return -EFAULT;		lock_sock(sk);		err = nf_getsockopt(sk, PF_INET6, optname, optval,				&len);		release_sock(sk);		if (err >= 0)			err = put_user(len, optlen);	}#endif	return err;}EXPORT_SYMBOL(ipv6_getsockopt);#ifdef CONFIG_COMPATint compat_ipv6_getsockopt(struct sock *sk, int level, int optname,			   char __user *optval, int __user *optlen){	int err;	if (level == SOL_IP && sk->sk_type != SOCK_RAW) {		if (udp_prot.compat_getsockopt != NULL)			return udp_prot.compat_getsockopt(sk, level, optname,							  optval, optlen);		return udp_prot.getsockopt(sk, level, optname, optval, optlen);	}	if (level != SOL_IPV6)		return -ENOPROTOOPT;	err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);#ifdef CONFIG_NETFILTER	/* we need to exclude all possible ENOPROTOOPTs except default case */	if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {		int len;		if (get_user(len, optlen))			return -EFAULT;		lock_sock(sk);		err = compat_nf_getsockopt(sk, PF_INET6,					   optname, optval, &len);		release_sock(sk);		if (err >= 0)			err = put_user(len, optlen);	}#endif	return err;}EXPORT_SYMBOL(compat_ipv6_getsockopt);#endifvoid __init ipv6_packet_init(void){	dev_add_pack(&ipv6_packet_type);}void ipv6_packet_cleanup(void){	dev_remove_pack(&ipv6_packet_type);}

⌨️ 快捷键说明

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