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

📄 ip_sockglue.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		err = -EINVAL;		if (sk->sk_bound_dev_if &&		    mreq.imr_ifindex != sk->sk_bound_dev_if)			break;		inet->mc_index = mreq.imr_ifindex;		inet->mc_addr  = mreq.imr_address.s_addr;		err = 0;		break;	}	case IP_ADD_MEMBERSHIP:	case IP_DROP_MEMBERSHIP:	{		struct ip_mreqn mreq;		err = -EPROTO;		if (inet_sk(sk)->is_icsk)			break;		if (optlen < sizeof(struct ip_mreq))			goto e_inval;		err = -EFAULT;		if (optlen >= sizeof(struct ip_mreqn)) {			if (copy_from_user(&mreq,optval,sizeof(mreq)))				break;		} else {			memset(&mreq, 0, sizeof(mreq));			if (copy_from_user(&mreq,optval,sizeof(struct ip_mreq)))				break;		}		if (optname == IP_ADD_MEMBERSHIP)			err = ip_mc_join_group(sk, &mreq);		else			err = ip_mc_leave_group(sk, &mreq);		break;	}	case IP_MSFILTER:	{		extern int sysctl_igmp_max_msf;		struct ip_msfilter *msf;		if (optlen < IP_MSFILTER_SIZE(0))			goto e_inval;		if (optlen > sysctl_optmem_max) {			err = -ENOBUFS;			break;		}		msf = kmalloc(optlen, GFP_KERNEL);		if (!msf) {			err = -ENOBUFS;			break;		}		err = -EFAULT;		if (copy_from_user(msf, optval, optlen)) {			kfree(msf);			break;		}		/* numsrc >= (1G-4) overflow in 32 bits */		if (msf->imsf_numsrc >= 0x3ffffffcU ||		    msf->imsf_numsrc > sysctl_igmp_max_msf) {			kfree(msf);			err = -ENOBUFS;			break;		}		if (IP_MSFILTER_SIZE(msf->imsf_numsrc) > optlen) {			kfree(msf);			err = -EINVAL;			break;		}		err = ip_mc_msfilter(sk, msf, 0);		kfree(msf);		break;	}	case IP_BLOCK_SOURCE:	case IP_UNBLOCK_SOURCE:	case IP_ADD_SOURCE_MEMBERSHIP:	case IP_DROP_SOURCE_MEMBERSHIP:	{		struct ip_mreq_source mreqs;		int omode, add;		if (optlen != sizeof(struct ip_mreq_source))			goto e_inval;		if (copy_from_user(&mreqs, optval, sizeof(mreqs))) {			err = -EFAULT;			break;		}		if (optname == IP_BLOCK_SOURCE) {			omode = MCAST_EXCLUDE;			add = 1;		} else if (optname == IP_UNBLOCK_SOURCE) {			omode = MCAST_EXCLUDE;			add = 0;		} else if (optname == IP_ADD_SOURCE_MEMBERSHIP) {			struct ip_mreqn mreq;			mreq.imr_multiaddr.s_addr = mreqs.imr_multiaddr;			mreq.imr_address.s_addr = mreqs.imr_interface;			mreq.imr_ifindex = 0;			err = ip_mc_join_group(sk, &mreq);			if (err && err != -EADDRINUSE)				break;			omode = MCAST_INCLUDE;			add = 1;		} else /* IP_DROP_SOURCE_MEMBERSHIP */ {			omode = MCAST_INCLUDE;			add = 0;		}		err = ip_mc_source(add, omode, sk, &mreqs, 0);		break;	}	case MCAST_JOIN_GROUP:	case MCAST_LEAVE_GROUP:	{		struct group_req greq;		struct sockaddr_in *psin;		struct ip_mreqn mreq;		if (optlen < sizeof(struct group_req))			goto e_inval;		err = -EFAULT;		if (copy_from_user(&greq, optval, sizeof(greq)))			break;		psin = (struct sockaddr_in *)&greq.gr_group;		if (psin->sin_family != AF_INET)			goto e_inval;		memset(&mreq, 0, sizeof(mreq));		mreq.imr_multiaddr = psin->sin_addr;		mreq.imr_ifindex = greq.gr_interface;		if (optname == MCAST_JOIN_GROUP)			err = ip_mc_join_group(sk, &mreq);		else			err = ip_mc_leave_group(sk, &mreq);		break;	}	case MCAST_JOIN_SOURCE_GROUP:	case MCAST_LEAVE_SOURCE_GROUP:	case MCAST_BLOCK_SOURCE:	case MCAST_UNBLOCK_SOURCE:	{		struct group_source_req greqs;		struct ip_mreq_source mreqs;		struct sockaddr_in *psin;		int omode, add;		if (optlen != sizeof(struct group_source_req))			goto e_inval;		if (copy_from_user(&greqs, optval, sizeof(greqs))) {			err = -EFAULT;			break;		}		if (greqs.gsr_group.ss_family != AF_INET ||		    greqs.gsr_source.ss_family != AF_INET) {			err = -EADDRNOTAVAIL;			break;		}		psin = (struct sockaddr_in *)&greqs.gsr_group;		mreqs.imr_multiaddr = psin->sin_addr.s_addr;		psin = (struct sockaddr_in *)&greqs.gsr_source;		mreqs.imr_sourceaddr = psin->sin_addr.s_addr;		mreqs.imr_interface = 0; /* use index for mc_source */		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 ip_mreqn mreq;			psin = (struct sockaddr_in *)&greqs.gsr_group;			mreq.imr_multiaddr = psin->sin_addr;			mreq.imr_address.s_addr = 0;			mreq.imr_ifindex = greqs.gsr_interface;			err = ip_mc_join_group(sk, &mreq);			if (err && err != -EADDRINUSE)				break;			greqs.gsr_interface = mreq.imr_ifindex;			omode = MCAST_INCLUDE;			add = 1;		} else /* MCAST_LEAVE_SOURCE_GROUP */ {			omode = MCAST_INCLUDE;			add = 0;		}		err = ip_mc_source(add, omode, sk, &mreqs,				   greqs.gsr_interface);		break;	}	case MCAST_MSFILTER:	{		extern int sysctl_igmp_max_msf;		struct sockaddr_in *psin;		struct ip_msfilter *msf = NULL;		struct group_filter *gsf = NULL;		int msize, i, ifindex;		if (optlen < GROUP_FILTER_SIZE(0))			goto e_inval;		if (optlen > sysctl_optmem_max) {			err = -ENOBUFS;			break;		}		gsf = kmalloc(optlen,GFP_KERNEL);		if (!gsf) {			err = -ENOBUFS;			break;		}		err = -EFAULT;		if (copy_from_user(gsf, optval, optlen)) {			goto mc_msf_out;		}		/* numsrc >= (4G-140)/128 overflow in 32 bits */		if (gsf->gf_numsrc >= 0x1ffffff ||		    gsf->gf_numsrc > sysctl_igmp_max_msf) {			err = -ENOBUFS;			goto mc_msf_out;		}		if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) {			err = -EINVAL;			goto mc_msf_out;		}		msize = IP_MSFILTER_SIZE(gsf->gf_numsrc);		msf = kmalloc(msize,GFP_KERNEL);		if (!msf) {			err = -ENOBUFS;			goto mc_msf_out;		}		ifindex = gsf->gf_interface;		psin = (struct sockaddr_in *)&gsf->gf_group;		if (psin->sin_family != AF_INET) {			err = -EADDRNOTAVAIL;			goto mc_msf_out;		}		msf->imsf_multiaddr = psin->sin_addr.s_addr;		msf->imsf_interface = 0;		msf->imsf_fmode = gsf->gf_fmode;		msf->imsf_numsrc = gsf->gf_numsrc;		err = -EADDRNOTAVAIL;		for (i=0; i<gsf->gf_numsrc; ++i) {			psin = (struct sockaddr_in *)&gsf->gf_slist[i];			if (psin->sin_family != AF_INET)				goto mc_msf_out;			msf->imsf_slist[i] = psin->sin_addr.s_addr;		}		kfree(gsf);		gsf = NULL;		err = ip_mc_msfilter(sk, msf, ifindex);	mc_msf_out:		kfree(msf);		kfree(gsf);		break;	}	case IP_ROUTER_ALERT:		err = ip_ra_control(sk, val ? 1 : 0, NULL);		break;	case IP_FREEBIND:		if (optlen<1)			goto e_inval;		inet->freebind = !!val;		break;	case IP_IPSEC_POLICY:	case IP_XFRM_POLICY:		err = -EPERM;		if (!capable(CAP_NET_ADMIN))			break;		err = xfrm_user_policy(sk, optname, optval, optlen);		break;	default:		err = -ENOPROTOOPT;		break;	}	release_sock(sk);	return err;e_inval:	release_sock(sk);	return -EINVAL;}int ip_setsockopt(struct sock *sk, int level,		int optname, char __user *optval, int optlen){	int err;	if (level != SOL_IP)		return -ENOPROTOOPT;	err = do_ip_setsockopt(sk, level, optname, optval, optlen);#ifdef CONFIG_NETFILTER	/* we need to exclude all possible ENOPROTOOPTs except default case */	if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&			optname != IP_IPSEC_POLICY &&			optname != IP_XFRM_POLICY &&			!ip_mroute_opt(optname)) {		lock_sock(sk);		err = nf_setsockopt(sk, PF_INET, optname, optval, optlen);		release_sock(sk);	}#endif	return err;}#ifdef CONFIG_COMPATint compat_ip_setsockopt(struct sock *sk, int level, int optname,			 char __user *optval, int optlen){	int err;	if (level != SOL_IP)		return -ENOPROTOOPT;	err = do_ip_setsockopt(sk, level, optname, optval, optlen);#ifdef CONFIG_NETFILTER	/* we need to exclude all possible ENOPROTOOPTs except default case */	if (err == -ENOPROTOOPT && optname != IP_HDRINCL &&			optname != IP_IPSEC_POLICY &&			optname != IP_XFRM_POLICY &&			!ip_mroute_opt(optname)) {		lock_sock(sk);		err = compat_nf_setsockopt(sk, PF_INET, optname,					   optval, optlen);		release_sock(sk);	}#endif	return err;}EXPORT_SYMBOL(compat_ip_setsockopt);#endif/* *	Get the options. Note for future reference. The GET of IP options gets the *	_received_ ones. The set sets the _sent_ ones. */static int do_ip_getsockopt(struct sock *sk, int level, int optname,			    char __user *optval, int __user *optlen){	struct inet_sock *inet = inet_sk(sk);	int val;	int len;	if (level != SOL_IP)		return -EOPNOTSUPP;	if (ip_mroute_opt(optname))		return ip_mroute_getsockopt(sk,optname,optval,optlen);	if (get_user(len,optlen))		return -EFAULT;	if (len < 0)		return -EINVAL;	lock_sock(sk);	switch (optname) {	case IP_OPTIONS:	{		unsigned char optbuf[sizeof(struct ip_options)+40];		struct ip_options * opt = (struct ip_options*)optbuf;		opt->optlen = 0;		if (inet->opt)			memcpy(optbuf, inet->opt,			       sizeof(struct ip_options)+			       inet->opt->optlen);		release_sock(sk);		if (opt->optlen == 0)			return put_user(0, optlen);		ip_options_undo(opt);		len = min_t(unsigned int, len, opt->optlen);		if (put_user(len, optlen))			return -EFAULT;		if (copy_to_user(optval, opt->__data, len))			return -EFAULT;		return 0;	}	case IP_PKTINFO:		val = (inet->cmsg_flags & IP_CMSG_PKTINFO) != 0;		break;	case IP_RECVTTL:		val = (inet->cmsg_flags & IP_CMSG_TTL) != 0;		break;	case IP_RECVTOS:		val = (inet->cmsg_flags & IP_CMSG_TOS) != 0;		break;	case IP_RECVOPTS:		val = (inet->cmsg_flags & IP_CMSG_RECVOPTS) != 0;		break;	case IP_RETOPTS:		val = (inet->cmsg_flags & IP_CMSG_RETOPTS) != 0;		break;	case IP_PASSSEC:		val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0;		break;	case IP_TOS:		val = inet->tos;		break;	case IP_TTL:		val = (inet->uc_ttl == -1 ?		       sysctl_ip_default_ttl :		       inet->uc_ttl);		break;	case IP_HDRINCL:		val = inet->hdrincl;		break;	case IP_MTU_DISCOVER:		val = inet->pmtudisc;		break;	case IP_MTU:	{		struct dst_entry *dst;		val = 0;		dst = sk_dst_get(sk);		if (dst) {			val = dst_mtu(dst);			dst_release(dst);		}		if (!val) {			release_sock(sk);			return -ENOTCONN;		}		break;	}	case IP_RECVERR:		val = inet->recverr;		break;	case IP_MULTICAST_TTL:		val = inet->mc_ttl;		break;	case IP_MULTICAST_LOOP:		val = inet->mc_loop;		break;	case IP_MULTICAST_IF:	{		struct in_addr addr;		len = min_t(unsigned int, len, sizeof(struct in_addr));		addr.s_addr = inet->mc_addr;		release_sock(sk);		if (put_user(len, optlen))			return -EFAULT;		if (copy_to_user(optval, &addr, len))			return -EFAULT;		return 0;	}	case IP_MSFILTER:	{		struct ip_msfilter msf;		int err;		if (len < IP_MSFILTER_SIZE(0)) {			release_sock(sk);			return -EINVAL;		}		if (copy_from_user(&msf, optval, IP_MSFILTER_SIZE(0))) {			release_sock(sk);			return -EFAULT;		}		err = ip_mc_msfget(sk, &msf,				   (struct ip_msfilter __user *)optval, optlen);		release_sock(sk);		return err;	}	case MCAST_MSFILTER:	{		struct group_filter gsf;		int err;		if (len < GROUP_FILTER_SIZE(0)) {			release_sock(sk);			return -EINVAL;		}		if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0))) {			release_sock(sk);			return -EFAULT;		}		err = ip_mc_gsfget(sk, &gsf,				   (struct group_filter __user *)optval, optlen);		release_sock(sk);		return err;	}	case IP_PKTOPTIONS:	{		struct msghdr msg;		release_sock(sk);		if (sk->sk_type != SOCK_STREAM)			return -ENOPROTOOPT;		msg.msg_control = optval;		msg.msg_controllen = len;		msg.msg_flags = 0;		if (inet->cmsg_flags & IP_CMSG_PKTINFO) {			struct in_pktinfo info;			info.ipi_addr.s_addr = inet->rcv_saddr;			info.ipi_spec_dst.s_addr = inet->rcv_saddr;			info.ipi_ifindex = inet->mc_index;			put_cmsg(&msg, SOL_IP, IP_PKTINFO, sizeof(info), &info);		}		if (inet->cmsg_flags & IP_CMSG_TTL) {			int hlim = inet->mc_ttl;			put_cmsg(&msg, SOL_IP, IP_TTL, sizeof(hlim), &hlim);		}		len -= msg.msg_controllen;		return put_user(len, optlen);	}	case IP_FREEBIND:		val = inet->freebind;		break;	default:		release_sock(sk);		return -ENOPROTOOPT;	}	release_sock(sk);	if (len < sizeof(int) && len > 0 && val>=0 && val<255) {		unsigned char ucval = (unsigned char)val;		len = 1;		if (put_user(len, optlen))			return -EFAULT;		if (copy_to_user(optval,&ucval,1))			return -EFAULT;	} else {		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 ip_getsockopt(struct sock *sk, int level,		  int optname, char __user *optval, int __user *optlen){	int err;	err = do_ip_getsockopt(sk, level, optname, optval, optlen);#ifdef CONFIG_NETFILTER	/* we need to exclude all possible ENOPROTOOPTs except default case */	if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS &&			!ip_mroute_opt(optname)) {		int len;		if (get_user(len,optlen))			return -EFAULT;		lock_sock(sk);		err = nf_getsockopt(sk, PF_INET, optname, optval,				&len);		release_sock(sk);		if (err >= 0)			err = put_user(len, optlen);		return err;	}#endif	return err;}#ifdef CONFIG_COMPATint compat_ip_getsockopt(struct sock *sk, int level, int optname,			 char __user *optval, int __user *optlen){	int err = do_ip_getsockopt(sk, level, optname, optval, optlen);#ifdef CONFIG_NETFILTER	/* we need to exclude all possible ENOPROTOOPTs except default case */	if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS &&			!ip_mroute_opt(optname)) {		int len;		if (get_user(len, optlen))			return -EFAULT;		lock_sock(sk);		err = compat_nf_getsockopt(sk, PF_INET, optname, optval, &len);		release_sock(sk);		if (err >= 0)			err = put_user(len, optlen);		return err;	}#endif	return err;}EXPORT_SYMBOL(compat_ip_getsockopt);#endifEXPORT_SYMBOL(ip_cmsg_recv);EXPORT_SYMBOL(ip_getsockopt);EXPORT_SYMBOL(ip_setsockopt);

⌨️ 快捷键说明

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