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

📄 datagram.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	/* Reset and regenerate socket error */	spin_lock_bh(&sk->sk_error_queue.lock);	sk->sk_err = 0;	if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) {		sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;		spin_unlock_bh(&sk->sk_error_queue.lock);		sk->sk_error_report(sk);	} else {		spin_unlock_bh(&sk->sk_error_queue.lock);	}out_free_skb:	kfree_skb(skb);out:	return err;}int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb){	struct ipv6_pinfo *np = inet6_sk(sk);	struct inet6_skb_parm *opt = IP6CB(skb);	unsigned char *nh = skb_network_header(skb);	if (np->rxopt.bits.rxinfo) {		struct in6_pktinfo src_info;		src_info.ipi6_ifindex = opt->iif;		ipv6_addr_copy(&src_info.ipi6_addr, &ipv6_hdr(skb)->daddr);		put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);	}	if (np->rxopt.bits.rxhlim) {		int hlim = ipv6_hdr(skb)->hop_limit;		put_cmsg(msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim);	}	if (np->rxopt.bits.rxtclass) {		int tclass = (ntohl(*(__be32 *)ipv6_hdr(skb)) >> 20) & 0xff;		put_cmsg(msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass);	}	if (np->rxopt.bits.rxflow && (*(__be32 *)nh & IPV6_FLOWINFO_MASK)) {		__be32 flowinfo = *(__be32 *)nh & IPV6_FLOWINFO_MASK;		put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo);	}	/* HbH is allowed only once */	if (np->rxopt.bits.hopopts && opt->hop) {		u8 *ptr = nh + opt->hop;		put_cmsg(msg, SOL_IPV6, IPV6_HOPOPTS, (ptr[1]+1)<<3, ptr);	}	if (opt->lastopt &&	    (np->rxopt.bits.dstopts || np->rxopt.bits.srcrt)) {		/*		 * Silly enough, but we need to reparse in order to		 * report extension headers (except for HbH)		 * in order.		 *		 * Also note that IPV6_RECVRTHDRDSTOPTS is NOT		 * (and WILL NOT be) defined because		 * IPV6_RECVDSTOPTS is more generic. --yoshfuji		 */		unsigned int off = sizeof(struct ipv6hdr);		u8 nexthdr = ipv6_hdr(skb)->nexthdr;		while (off <= opt->lastopt) {			unsigned len;			u8 *ptr = nh + off;			switch(nexthdr) {			case IPPROTO_DSTOPTS:				nexthdr = ptr[0];				len = (ptr[1] + 1) << 3;				if (np->rxopt.bits.dstopts)					put_cmsg(msg, SOL_IPV6, IPV6_DSTOPTS, len, ptr);				break;			case IPPROTO_ROUTING:				nexthdr = ptr[0];				len = (ptr[1] + 1) << 3;				if (np->rxopt.bits.srcrt)					put_cmsg(msg, SOL_IPV6, IPV6_RTHDR, len, ptr);				break;			case IPPROTO_AH:				nexthdr = ptr[0];				len = (ptr[1] + 2) << 2;				break;			default:				nexthdr = ptr[0];				len = (ptr[1] + 1) << 3;				break;			}			off += len;		}	}	/* socket options in old style */	if (np->rxopt.bits.rxoinfo) {		struct in6_pktinfo src_info;		src_info.ipi6_ifindex = opt->iif;		ipv6_addr_copy(&src_info.ipi6_addr, &ipv6_hdr(skb)->daddr);		put_cmsg(msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info);	}	if (np->rxopt.bits.rxohlim) {		int hlim = ipv6_hdr(skb)->hop_limit;		put_cmsg(msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim);	}	if (np->rxopt.bits.ohopopts && opt->hop) {		u8 *ptr = nh + opt->hop;		put_cmsg(msg, SOL_IPV6, IPV6_2292HOPOPTS, (ptr[1]+1)<<3, ptr);	}	if (np->rxopt.bits.odstopts && opt->dst0) {		u8 *ptr = nh + opt->dst0;		put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr);	}	if (np->rxopt.bits.osrcrt && opt->srcrt) {		struct ipv6_rt_hdr *rthdr = (struct ipv6_rt_hdr *)(nh + opt->srcrt);		put_cmsg(msg, SOL_IPV6, IPV6_2292RTHDR, (rthdr->hdrlen+1) << 3, rthdr);	}	if (np->rxopt.bits.odstopts && opt->dst1) {		u8 *ptr = nh + opt->dst1;		put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr);	}	return 0;}int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,		      struct ipv6_txoptions *opt,		      int *hlimit, int *tclass){	struct in6_pktinfo *src_info;	struct cmsghdr *cmsg;	struct ipv6_rt_hdr *rthdr;	struct ipv6_opt_hdr *hdr;	int len;	int err = 0;	for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {		int addr_type;		struct net_device *dev = NULL;		if (!CMSG_OK(msg, cmsg)) {			err = -EINVAL;			goto exit_f;		}		if (cmsg->cmsg_level != SOL_IPV6)			continue;		switch (cmsg->cmsg_type) {		case IPV6_PKTINFO:		case IPV6_2292PKTINFO:			if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct in6_pktinfo))) {				err = -EINVAL;				goto exit_f;			}			src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg);			if (src_info->ipi6_ifindex) {				if (fl->oif && src_info->ipi6_ifindex != fl->oif)					return -EINVAL;				fl->oif = src_info->ipi6_ifindex;			}			addr_type = ipv6_addr_type(&src_info->ipi6_addr);			if (addr_type == IPV6_ADDR_ANY)				break;			if (addr_type & IPV6_ADDR_LINKLOCAL) {				if (!src_info->ipi6_ifindex)					return -EINVAL;				else {					dev = dev_get_by_index(&init_net, src_info->ipi6_ifindex);					if (!dev)						return -ENODEV;				}			}			if (!ipv6_chk_addr(&src_info->ipi6_addr, dev, 0)) {				if (dev)					dev_put(dev);				err = -EINVAL;				goto exit_f;			}			if (dev)				dev_put(dev);			ipv6_addr_copy(&fl->fl6_src, &src_info->ipi6_addr);			break;		case IPV6_FLOWINFO:			if (cmsg->cmsg_len < CMSG_LEN(4)) {				err = -EINVAL;				goto exit_f;			}			if (fl->fl6_flowlabel&IPV6_FLOWINFO_MASK) {				if ((fl->fl6_flowlabel^*(__be32 *)CMSG_DATA(cmsg))&~IPV6_FLOWINFO_MASK) {					err = -EINVAL;					goto exit_f;				}			}			fl->fl6_flowlabel = IPV6_FLOWINFO_MASK & *(__be32 *)CMSG_DATA(cmsg);			break;		case IPV6_2292HOPOPTS:		case IPV6_HOPOPTS:			if (opt->hopopt || cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) {				err = -EINVAL;				goto exit_f;			}			hdr = (struct ipv6_opt_hdr *)CMSG_DATA(cmsg);			len = ((hdr->hdrlen + 1) << 3);			if (cmsg->cmsg_len < CMSG_LEN(len)) {				err = -EINVAL;				goto exit_f;			}			if (!capable(CAP_NET_RAW)) {				err = -EPERM;				goto exit_f;			}			opt->opt_nflen += len;			opt->hopopt = hdr;			break;		case IPV6_2292DSTOPTS:			if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) {				err = -EINVAL;				goto exit_f;			}			hdr = (struct ipv6_opt_hdr *)CMSG_DATA(cmsg);			len = ((hdr->hdrlen + 1) << 3);			if (cmsg->cmsg_len < CMSG_LEN(len)) {				err = -EINVAL;				goto exit_f;			}			if (!capable(CAP_NET_RAW)) {				err = -EPERM;				goto exit_f;			}			if (opt->dst1opt) {				err = -EINVAL;				goto exit_f;			}			opt->opt_flen += len;			opt->dst1opt = hdr;			break;		case IPV6_DSTOPTS:		case IPV6_RTHDRDSTOPTS:			if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) {				err = -EINVAL;				goto exit_f;			}			hdr = (struct ipv6_opt_hdr *)CMSG_DATA(cmsg);			len = ((hdr->hdrlen + 1) << 3);			if (cmsg->cmsg_len < CMSG_LEN(len)) {				err = -EINVAL;				goto exit_f;			}			if (!capable(CAP_NET_RAW)) {				err = -EPERM;				goto exit_f;			}			if (cmsg->cmsg_type == IPV6_DSTOPTS) {				opt->opt_flen += len;				opt->dst1opt = hdr;			} else {				opt->opt_nflen += len;				opt->dst0opt = hdr;			}			break;		case IPV6_2292RTHDR:		case IPV6_RTHDR:			if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_rt_hdr))) {				err = -EINVAL;				goto exit_f;			}			rthdr = (struct ipv6_rt_hdr *)CMSG_DATA(cmsg);			switch (rthdr->type) {#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)			case IPV6_SRCRT_TYPE_2:				break;#endif			default:				err = -EINVAL;				goto exit_f;			}			len = ((rthdr->hdrlen + 1) << 3);			if (cmsg->cmsg_len < CMSG_LEN(len)) {				err = -EINVAL;				goto exit_f;			}			/* segments left must also match */			if ((rthdr->hdrlen >> 1) != rthdr->segments_left) {				err = -EINVAL;				goto exit_f;			}			opt->opt_nflen += len;			opt->srcrt = rthdr;			if (cmsg->cmsg_type == IPV6_2292RTHDR && opt->dst1opt) {				int dsthdrlen = ((opt->dst1opt->hdrlen+1)<<3);				opt->opt_nflen += dsthdrlen;				opt->dst0opt = opt->dst1opt;				opt->dst1opt = NULL;				opt->opt_flen -= dsthdrlen;			}			break;		case IPV6_2292HOPLIMIT:		case IPV6_HOPLIMIT:			if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) {				err = -EINVAL;				goto exit_f;			}			*hlimit = *(int *)CMSG_DATA(cmsg);			break;		case IPV6_TCLASS:		    {			int tc;			err = -EINVAL;			if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) {				goto exit_f;			}			tc = *(int *)CMSG_DATA(cmsg);			if (tc < -1 || tc > 0xff)				goto exit_f;			err = 0;			*tclass = tc;			break;		    }		default:			LIMIT_NETDEBUG(KERN_DEBUG "invalid cmsg type: %d\n",				       cmsg->cmsg_type);			err = -EINVAL;			break;		}	}exit_f:	return err;}

⌨️ 快捷键说明

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